--- /dev/null
+requires: drivers_uart drivers_of libc_minimal l4util cxx_io
+Maintainer: adam@os.inf.tu-dresden.de warg@os.inf.tu-dresden.de
--- /dev/null
+# Format: (all on one line)
+# Source file : Copyright Owner(s) : License
+# Please use "TUD" when referring to TU Dresden.
+# If sole owner is TUD, the license field defaults to GPL and can be
+# left empty.
+# Source-file spec can be a directory name or a wildcard like "src/*.c".
+Makefile : TUD
+server/Makefile : TUD
+server/src/ARCH-x86/bootsect.S : GPL
+server/src/ARCH-x86/bootstrap.ld.in : TUD
+server/src/ARCH-x86/crt0.S : TUD
+server/src/ARCH-x86/oskit_support.c : TUD
+server/src/ARCH-x86/serial.c : TUD
+server/src/ARCH-x86/serial.h : TUD
+server/src/ARCH-x86/setup.S : GPL
+server/src/ARCH-x86/xen.c
+server/src/ARCH-arm/bootstrap.ld.in : TUD
+server/src/Makefile : TUD
+server/src/base_critical.c : TUD
+server/src/base_critical.h : TUD
+server/src/build.pl : TUD
+server/src/exec.c : TUD
+server/src/exec.h : TUD
+server/src/gunzip.c : GPL
+server/src/gunzip.h : GPL
+server/src/init.h : TUD
+server/src/init_hazelnut.c : TUD
+server/src/init_ibm_nucleus.c : TUD
+server/src/init_l4_gmd.c : TUD
+server/src/libc_support.c : TUD
+server/src/loader_mbi.c : TUD
+server/src/loader_mbi.h : TUD
+server/src/module.h : TUD
+server/src/modules.list : TUD
+server/src/region.c : TUD
+server/src/region.h : TUD
+server/src/startup.c : TUD
+server/src/startup.h : TUD
+server/src/types.h : TUD : TUD
+server/src/uncompress.c : TUD
+server/src/uncompress.h : TUD
+server/src/version.h : TUD
+
--- /dev/null
+PKGDIR = .
+L4DIR ?= $(PKGDIR)/../..
+
+include $(L4DIR)/mk/subdir.mk
--- /dev/null
+L4 Bootstrapper for booting Fiasco and other L4 compatible kernels.
+
+Command line parameters (in alphabetical order):
+
+ -comport=<port>
+ If serial logging is enabled, <port> defines which serial port to use,
+ where 1 is the first port found.
+ NOTE: Bootstrap does not support the -comspeed=<speed> option and uses
+ the port with 115200 bps.
+
+ -hercules
+ --- DOCUMENTATION MISSING ---
+
+ -maxmem=<size in MB>
+ Set the mem_upper field of the multiboot info structure.
+
+ -patch=<modname>,<text>=<replacement>,...
+ <modname> is compared with the path name of each module to decide which
+ module should be patched. If the module was found, each occurrence of
+ <text> is replaced by <replacement>. <replacement> can also be quoted
+ text. Otherwise no spaces are allowed.
+
+ -arg=<modname>,<replacement>
+ <modname> is compared with the path name of each module to decide which
+ module arguments should be replaced. If the module was found, the module
+ arguments, that is all text of the module command line after the first
+ ' ' is replaced by <replacement>. <replacement> can also be quoted text.
+
+ -roottask
+ No effect -- Provided for compatibility with RMGR.
+
+ -serial
+ Enables support for logging to serial line.
+
+ -sigma0
+ No effect -- Provided for compatibility with RMGR.
+
+ -modaddr=<addr>
+ Relocate modules to the physical address ADDR. Eliminates the
+ need for a specialized GRUB that supports the modaddr command.
--- /dev/null
+PKGDIR ?= ..
+L4DIR ?= $(PKGDIR)/../..
+
+include $(L4DIR)/mk/subdir.mk
--- /dev/null
+/*
+ * (c) 2009 Frank Mehnert <fm3@os.inf.tu-dresden.de>,
+ * Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+/* -*- c -*- */
+
+ .globl _start
+ .p2align 4
+_start:
+#ifdef REALMODE_LOADING
+ cld
+ cli
+ mov $(3 * 8), %eax
+ mov %eax, %ds
+ mov %eax, %es
+ mov %eax, %fs
+ mov %eax, %gs
+
+ /* We have the following problem: Our image is loaded at 0x00100000
+ * by the boot loader but we don't want to get into conflict with
+ * the AMD64 executable. Therefore we move ourself out of the way.
+ * We are linked to 0x01000000 (see ARCH-amd64/boot32/bootstrap.ld) */
+ mov %esi, %ebx
+ mov $0x00100000, %esi
+ mov $0x01000000, %edi
+ mov $_image_end, %ecx
+ sub $_image_start, %ecx
+ rep movsb
+ mov $1f, %eax
+ jmp *%eax
+1: mov %ebx, %esi
+ lss _stack_seg, %esp
+#else
+ leal _stack,%esp
+#endif
+
+ pushl %esi /* ptr to real mode */
+ pushl %eax
+ pushl %ebx
+ pushl $0 /* no return address */
+ jmp bootstrap
+
+ .align 4
+
+ .p2align(2), 0x90
+ .long 0x1BADB002 /* magic */
+ .long 0x00000000 /* feature flags */
+ .long 0 - 0x1BADB002
+
+#ifdef REALMODE_LOADING
+_stack_seg:
+ .long _stack
+ .word (3 * 8)
+#endif
+
+ .bss
+ .space 8192
+_stack:
--- /dev/null
+/*
+ * (c) 2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ * Frank Mehnert <fm3@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "types.h"
+#include "boot_cpu.h"
+#include "boot_paging.h"
+
+
+unsigned KERNEL_CS_64 = 0x20; // XXX
+
+enum
+{
+ PML4ESHIFT = 38,
+ PML4EMASK = 0x1ff,
+ PDPESHIFT = 30,
+ PDPEMASK = 0x1ff,
+ PDESHIFT = 21,
+ PDEMASK = 0x1ff,
+ PTESHIFT = 12,
+ PTEMASK = 0x1ff,
+
+ INTEL_PTE_VALID = 0x0000000000000001LL,
+ INTEL_PTE_WRITE = 0x0000000000000002LL,
+ INTEL_PTE_USER = 0x0000000000000004LL,
+ INTEL_PTE_WTHRU = 0x00000008,
+ INTEL_PTE_NCACHE = 0x00000010,
+ INTEL_PTE_REF = 0x00000020,
+ INTEL_PTE_MOD = 0x00000040,
+ INTEL_PTE_GLOBAL = 0x00000100,
+ INTEL_PTE_AVAIL = 0x00000e00,
+ INTEL_PTE_PFN = 0x000ffffffffff000LL,
+
+ INTEL_PDE_VALID = 0x0000000000000001LL,
+ INTEL_PDE_WRITE = 0x0000000000000002LL,
+ INTEL_PDE_USER = 0x0000000000000004LL,
+ INTEL_PDE_WTHRU = 0x00000008,
+ INTEL_PDE_NCACHE = 0x00000010,
+ INTEL_PDE_REF = 0x00000020,
+ INTEL_PDE_MOD = 0x00000040,
+ INTEL_PDE_SUPERPAGE = 0x0000000000000080LL,
+ INTEL_PDE_GLOBAL = 0x00000100,
+ INTEL_PDE_AVAIL = 0x00000e00,
+ INTEL_PDE_PFN = 0x000ffffffffff000LL,
+
+ INTEL_PDPE_VALID = 0x0000000000000001LL,
+ INTEL_PDPE_WRITE = 0x0000000000000002LL,
+ INTEL_PDPE_USER = 0x0000000000000004LL,
+ INTEL_PDPE_PFN = 0x000ffffffffff000LL,
+
+ INTEL_PML4E_VALID = 0x0000000000000001LL,
+ INTEL_PML4E_WRITE = 0x0000000000000002LL,
+ INTEL_PML4E_USER = 0x0000000000000004LL,
+ INTEL_PML4E_PFN = 0x000ffffffffff000LL,
+
+ CPUF_4MB_PAGES = 0x00000008,
+
+ CR0_PG = 0x80000000,
+ CR4_PSE = 0x00000010,
+ CR4_PAE = 0x00000020,
+ EFL_AC = 0x00040000,
+ EFL_ID = 0x00200000,
+ EFER_LME = 0x00000100,
+
+ BASE_TSS = 0x08,
+ KERNEL_CS = 0x10,
+ KERNEL_DS = 0x18,
+
+ DBF_TSS = 0x28, // XXX check this value
+
+ ACC_TSS = 0x09,
+ ACC_TSS_BUSY = 0x02,
+ ACC_CODE_R = 0x1a,
+ ACC_DATA_W = 0x12,
+ ACC_PL_K = 0x00,
+ ACC_P = 0x80,
+ SZ_32 = 0x4,
+ SZ_16 = 0x0,
+ SZ_G = 0x8,
+ SZ_CODE_64 = 0x2, // XXX 64 Bit Code Segment
+
+ GDTSZ = (0x30/8), // XXX check this value
+ IDTSZ = 256,
+};
+
+
+struct pseudo_descriptor
+{
+ l4_uint16_t pad;
+ l4_uint16_t limit;
+ l4_uint32_t linear_base;
+};
+
+struct x86_desc
+{
+ l4_uint16_t limit_low; /* limit 0..15 */
+ l4_uint16_t base_low; /* base 0..15 */
+ l4_uint8_t base_med; /* base 16..23 */
+ l4_uint8_t access; /* access byte */
+ l4_uint8_t limit_high:4; /* limit 16..19 */
+ l4_uint8_t granularity:4; /* granularity */
+ l4_uint8_t base_high; /* base 24..31 */
+} __attribute__((packed));
+
+struct x86_gate
+{
+ l4_uint16_t offset_low; /* offset 0..15 */
+ l4_uint16_t selector;
+ l4_uint8_t word_count;
+ l4_uint8_t access;
+ l4_uint16_t offset_high; /* offset 16..31 */
+} __attribute__((packed));
+
+struct x86_tss
+{
+ l4_uint32_t back_link;
+ l4_uint32_t esp0, ss0;
+ l4_uint32_t esp1, ss1;
+ l4_uint32_t esp2, ss2;
+ l4_uint32_t cr3;
+ l4_uint32_t eip, eflags;
+ l4_uint32_t eax, ecx, edx, ebx, esp, ebp, esi, edi;
+ l4_uint32_t es, cs, ss, ds, fs, gs;
+ l4_uint32_t ldt;
+ l4_uint16_t trace_trap;
+ l4_uint16_t io_bit_map_offset;
+};
+
+struct gate_init_entry
+{
+ l4_uint32_t entrypoint;
+ l4_uint16_t vector;
+ l4_uint16_t type;
+};
+
+struct trap_state
+{
+ l4_uint32_t gs, fs, es, ds;
+ l4_uint32_t edi, esi, ebp, cr2, ebx, edx, ecx, eax;
+ l4_uint32_t trapno, err;
+ l4_uint32_t eip, cs, eflags, esp, ss;
+};
+
+static l4_uint32_t cpu_feature_flags;
+static l4_uint32_t base_pml4_pa;
+static struct x86_tss base_tss;
+static struct x86_desc base_gdt[GDTSZ];
+static struct x86_gate base_idt[IDTSZ];
+
+static void handle_dbf(void);
+static char dbf_stack[2048];
+static struct x86_tss dbf_tss =
+ {
+ 0/*back_link*/,
+ 0/*esp0*/, 0/*ss0*/, 0/*esp1*/, 0/*ss1*/, 0/*esp2*/, 0/*ss2*/,
+ 0/*cr3*/,
+ (l4_uint32_t)handle_dbf/*eip*/, 0x00000082/*eflags*/,
+ 0/*eax*/, 0/*ecx*/, 0/*edx*/, 0/*ebx*/,
+ (l4_uint32_t)dbf_stack + sizeof(dbf_stack)/*esp*/,
+ 0/*ebp*/, 0/*esi*/, 0/*edi*/,
+ KERNEL_DS/*es*/, KERNEL_CS/*cs*/, KERNEL_DS/*ss*/,
+ KERNEL_DS/*ds*/, KERNEL_DS/*fs*/, KERNEL_DS/*gs*/,
+ 0/*ldt*/, 0/*trace_trap*/, 0x8000/*io_bit_map_offset*/
+ };
+
+static inline l4_uint64_t* find_pml4e(l4_uint32_t pml4_pa, l4_uint64_t la)
+{ return (&((l4_uint64_t*)pml4_pa)[(la >> PML4ESHIFT) & PML4EMASK]); }
+
+static inline l4_uint64_t* find_pdpe(l4_uint32_t pdp_pa, l4_uint64_t la)
+{ return (&((l4_uint64_t*)pdp_pa)[(la >> PDPESHIFT) & PDPEMASK]); }
+
+static inline l4_uint64_t* find_pde(l4_uint32_t pdir_pa, l4_uint64_t la)
+{ return (&((l4_uint64_t*)pdir_pa)[(la >> PDESHIFT) & PDEMASK]); }
+
+static inline l4_uint64_t* find_pte(l4_uint32_t ptab_pa, l4_uint64_t la)
+{ return (&((l4_uint64_t*)ptab_pa)[(la >> PTESHIFT) & PTEMASK]); }
+
+static inline l4_uint32_t get_eflags(void)
+{ l4_uint32_t efl; asm volatile("pushf ; popl %0" : "=r" (efl)); return efl; }
+
+static inline void set_eflags(l4_uint32_t efl)
+{ asm volatile("pushl %0 ; popf" : : "r" (efl) : "memory"); }
+
+static inline void set_ds(l4_uint16_t ds)
+{ asm volatile("movw %w0,%%ds" : : "r" (ds)); }
+
+static inline void set_es(l4_uint16_t es)
+{ asm volatile("movw %w0,%%es" : : "r" (es)); }
+
+static inline void set_fs(l4_uint16_t fs)
+{ asm volatile("movw %w0,%%fs" : : "r" (fs)); }
+
+static inline void set_gs(l4_uint16_t gs)
+{ asm volatile("movw %w0,%%gs" : : "r" (gs)); }
+
+static inline void set_ss(l4_uint16_t ss)
+{ asm volatile("movw %w0,%%ss" : : "r" (ss)); }
+
+static inline l4_uint16_t get_ss(void)
+{ l4_uint16_t ss; asm volatile("movw %%ss,%w0" : "=r" (ss)); return ss; }
+
+#define set_idt(pseudo_desc) \
+ asm volatile("lidt %0" : : "m" ((pseudo_desc)->limit) : "memory")
+
+#define set_gdt(pseudo_desc) \
+ asm volatile("lgdt %0" : : "m" ((pseudo_desc)->limit) : "memory")
+
+#define set_tr(seg) \
+ asm volatile("ltr %0" : : "rm" ((l4_uint16_t)(seg)))
+
+#define get_esp() \
+ ({ register l4_uint32_t _temp__; \
+ asm("movl %%esp, %0" : "=r" (_temp__)); _temp__; })
+
+#define get_cr0() \
+ ({ register l4_uint32_t _temp__; \
+ asm volatile("mov %%cr0, %0" : "=r" (_temp__)); _temp__; })
+
+#define set_cr3(value) \
+ ({ register l4_uint32_t _temp__ = (value); \
+ asm volatile("mov %0, %%cr3" : : "r" (_temp__)); })
+
+#define get_cr4() \
+ ({ register l4_uint32_t _temp__; \
+ asm volatile("mov %%cr4, %0" : "=r" (_temp__)); _temp__; })
+
+#define set_cr4(value) \
+ ({ register l4_uint32_t _temp__ = (value); \
+ asm volatile("mov %0, %%cr4" : : "r" (_temp__)); })
+
+
+static inline void enable_longmode(void)
+{
+ l4_uint32_t dummy;
+ asm volatile("rdmsr; bts $8, %%eax; wrmsr"
+ :"=a"(dummy), "=d"(dummy) : "c"(0xc0000080));
+}
+
+static inline void
+fill_descriptor(struct x86_desc *desc, l4_uint32_t base, l4_uint32_t limit,
+ l4_uint8_t access, l4_uint8_t sizebits)
+{
+ if (limit > 0xfffff)
+ {
+ limit >>= 12;
+ sizebits |= SZ_G;
+ }
+ desc->limit_low = limit & 0xffff;
+ desc->base_low = base & 0xffff;
+ desc->base_med = (base >> 16) & 0xff;
+ desc->access = access | ACC_P;
+ desc->limit_high = limit >> 16;
+ desc->granularity = sizebits;
+ desc->base_high = base >> 24;
+}
+
+static inline void
+fill_gate(struct x86_gate *gate, l4_uint32_t offset,
+ l4_uint16_t selector, l4_uint8_t access)
+{
+ gate->offset_low = offset & 0xffff;
+ gate->selector = selector;
+ gate->word_count = 0;
+ gate->access = access | ACC_P;
+ gate->offset_high = (offset >> 16) & 0xffff;
+}
+
+static inline void
+paging_enable(l4_uint32_t pml4)
+{
+ /* Enable Physical l4_uint64_t Extension (PAE). */
+ set_cr4(get_cr4() | CR4_PAE);
+
+ /* Load the page map level 4. */
+ set_cr3(pml4);
+
+ /* Enable long mode. */
+ enable_longmode();
+
+ /* Turn on paging and switch to long mode. */
+ asm volatile("movl %0,%%cr0 ; jmp 1f ; 1:" : : "r" (get_cr0() | CR0_PG));
+}
+
+static void
+panic(const char *str)
+{
+ printf("PANIC: %s\n", str);
+ while (1)
+ ;
+ _exit(-1);
+}
+
+static void
+cpuid(void)
+{
+ int orig_eflags = get_eflags();
+
+ /* Check for a dumb old 386 by trying to toggle the AC flag. */
+ set_eflags(orig_eflags ^ EFL_AC);
+ if ((get_eflags() ^ orig_eflags) & EFL_AC)
+ {
+ /* It's a 486 or better. Now try toggling the ID flag. */
+ set_eflags(orig_eflags ^ EFL_ID);
+ if ((get_eflags() ^ orig_eflags) & EFL_ID)
+ {
+ int highest_val, dummy;
+ asm volatile("cpuid"
+ : "=a" (highest_val)
+ : "a" (0) : "ebx", "ecx", "edx");
+
+ if (highest_val >= 1)
+ {
+ asm volatile("cpuid"
+ : "=a" (dummy),
+ "=d" (cpu_feature_flags)
+ : "a" (1)
+ : "ebx", "ecx");
+ }
+ }
+ }
+
+ set_eflags(orig_eflags);
+}
+
+extern struct gate_init_entry boot_idt_inittab[];
+static void
+base_idt_init(void)
+{
+ struct x86_gate *dst = base_idt;
+ const struct gate_init_entry *src = boot_idt_inittab;
+
+ while (src->entrypoint)
+ {
+ if ((src->type & 0x1f) == 0x05)
+ // task gate
+ fill_gate(&dst[src->vector], 0, src->entrypoint, src->type);
+ else
+ // interrupt gate
+ fill_gate(&dst[src->vector], src->entrypoint, KERNEL_CS, src->type);
+ src++;
+ }
+}
+
+static void
+base_gdt_init(void)
+{
+ /* Initialize the base TSS descriptor. */
+ fill_descriptor(&base_gdt[BASE_TSS / 8],
+ (l4_uint32_t)&base_tss, sizeof(base_tss) - 1,
+ ACC_PL_K | ACC_TSS, 0);
+ /* Initialize the TSS descriptor for the double fault handler */
+ fill_descriptor(&base_gdt[DBF_TSS / 8],
+ (l4_uint32_t)&dbf_tss, sizeof(dbf_tss) - 1,
+ ACC_PL_K | ACC_TSS, 0);
+ /* Initialize the 32-bit kernel code and data segment descriptors
+ to point to the base of the kernel linear space region. */
+ fill_descriptor(&base_gdt[KERNEL_CS / 8], 0, 0xffffffff,
+ ACC_PL_K | ACC_CODE_R, SZ_32);
+ fill_descriptor(&base_gdt[KERNEL_DS / 8], 0, 0xffffffff,
+ ACC_PL_K | ACC_DATA_W, SZ_32);
+ /* XXX Initialize the 64-bit kernel code segment descriptor */
+ fill_descriptor(&base_gdt[KERNEL_CS_64 / 8], 0, 0xffffffff,
+ ACC_PL_K | ACC_CODE_R, SZ_CODE_64);
+}
+
+static void
+base_tss_init(void)
+{
+ base_tss.ss0 = KERNEL_DS;
+ base_tss.esp0 = get_esp(); /* only temporary */
+ base_tss.io_bit_map_offset = sizeof(base_tss);
+}
+
+static void
+base_gdt_load(void)
+{
+ struct pseudo_descriptor pdesc;
+
+ /* Create a pseudo-descriptor describing the GDT. */
+ pdesc.limit = sizeof(base_gdt) - 1;
+ pdesc.linear_base = (l4_uint32_t)&base_gdt;
+
+ /* Load it into the CPU. */
+ set_gdt(&pdesc);
+
+ /* Reload all the segment registers from the new GDT. */
+ asm volatile("ljmp %0,$1f ; 1:" : : "i" (KERNEL_CS));
+ set_ds(KERNEL_DS);
+ set_es(KERNEL_DS);
+ set_ss(KERNEL_DS);
+ set_fs(0);
+ set_gs(0);
+}
+
+static void
+base_idt_load(void)
+{
+ struct pseudo_descriptor pdesc;
+
+ /* Create a pseudo-descriptor describing the GDT. */
+ pdesc.limit = sizeof(base_idt) - 1;
+ pdesc.linear_base = (l4_uint32_t)&base_idt;
+ set_idt(&pdesc);
+}
+
+static void
+base_tss_load(void)
+{
+ /* Make sure the TSS isn't marked busy. */
+ base_gdt[BASE_TSS / 8].access &= ~ACC_TSS_BUSY;
+ asm volatile ("" : : : "memory");
+ set_tr(BASE_TSS);
+}
+
+void
+base_cpu_setup(void)
+{
+ cpuid();
+ base_idt_init();
+ base_gdt_init();
+ base_tss_init();
+ // force tables to memory before loading segment registers
+ asm volatile ("" : : : "memory");
+ base_gdt_load();
+ base_idt_load();
+ base_tss_load();
+}
+
+struct ptab64_mem_info_t ptab64_mem_info;
+
+static void
+ptab_alloc(l4_uint32_t *out_ptab_pa)
+{
+ static char pool[6 << 12] __attribute__((aligned(4096)));
+ static l4_uint32_t pdirs;
+ static int initialized;
+
+ if (! initialized)
+ {
+ initialized = 1;
+ ptab64_mem_info.addr = (l4_uint32_t)pool;
+ ptab64_mem_info.size = sizeof(pool);
+ memset(pool, 0, sizeof(pool));
+ pdirs = ((l4_uint32_t)pool + PAGE_SIZE - 1) & ~PAGE_MASK;
+ }
+
+ if (pdirs > (l4_uint32_t)pool + sizeof(pool))
+ panic("Cannot allocate page table -- increase ptab_alloc::pool");
+
+ *out_ptab_pa = pdirs;
+ pdirs += PAGE_SIZE;
+}
+
+static void
+pdir_map_range(l4_uint32_t pml4_pa, l4_uint64_t la, l4_uint64_t pa,
+ l4_uint64_t size, l4_uint32_t mapping_bits)
+{
+ assert(size);
+ assert(la+size-1 > la); // avoid 4GB wrap around
+
+ while (size > 0)
+ {
+ l4_uint64_t *pml4e = find_pml4e(pml4_pa, la);
+
+ /* Create new pml4e with corresponding pdp (page directory pointer)
+ * if no valid entry exists. */
+ if (!(*pml4e & INTEL_PML4E_VALID))
+ {
+ l4_uint32_t pdp_pa;
+
+ /* Allocate new page for pdp. */
+ ptab_alloc(&pdp_pa);
+
+ /* Set the pml4 to point to it. */
+ *pml4e = (pdp_pa & INTEL_PML4E_PFN)
+ | INTEL_PML4E_VALID | INTEL_PML4E_USER | INTEL_PML4E_WRITE;
+ }
+
+ do
+ {
+ l4_uint64_t *pdpe = find_pdpe(*pml4e & INTEL_PML4E_PFN, la);
+
+ /* Create new pdpe with corresponding pd (page directory)
+ * if no valid entry exists. */
+ if (!(*pdpe & INTEL_PDPE_VALID))
+ {
+ l4_uint32_t pd_pa;
+
+ /* Allocate new page for pd. */
+ ptab_alloc(&pd_pa);
+
+ /* Set the pdpe to point to it. */
+ *pdpe = (pd_pa & INTEL_PDPE_PFN)
+ | INTEL_PDPE_VALID | INTEL_PDPE_USER | INTEL_PDPE_WRITE;
+ }
+
+ do
+ {
+ l4_uint64_t *pde = find_pde(*pdpe & INTEL_PDPE_PFN, la);
+
+ /* Use a 2MB page if we can. */
+ if (superpage_aligned(la) && superpage_aligned(pa)
+ && (size >= SUPERPAGE_SIZE))
+ //&& (cpu_feature_flags & CPUF_4MB_PAGES)) XXX
+ {
+ /* a failed assertion here may indicate a memory wrap
+ around problem */
+ assert(!(*pde & INTEL_PDE_VALID));
+ /* XXX what if an empty page table exists
+ from previous finer-granularity mappings? */
+ *pde = pa | mapping_bits | INTEL_PDE_SUPERPAGE;
+ la += SUPERPAGE_SIZE;
+ pa += SUPERPAGE_SIZE;
+ size -= SUPERPAGE_SIZE;
+ }
+ else
+ {
+ /* Find the page table, creating one if necessary. */
+ if (!(*pde & INTEL_PDE_VALID))
+ {
+ l4_uint32_t ptab_pa;
+
+ /* Allocate a new page table. */
+ ptab_alloc(&ptab_pa);
+
+ /* Set the pde to point to it. */
+ *pde = (ptab_pa & INTEL_PTE_PFN)
+ | INTEL_PDE_VALID | INTEL_PDE_USER | INTEL_PDE_WRITE;
+ }
+ assert(!(*pde & INTEL_PDE_SUPERPAGE));
+
+
+ /* Use normal 4KB page mappings. */
+ do
+ {
+ l4_uint64_t *pte = find_pte(*pde & INTEL_PDE_PFN, la);
+ assert(!(*pte & INTEL_PTE_VALID));
+
+ /* Insert the mapping. */
+ *pte = pa | mapping_bits;
+
+ /* Advance to the next page. */
+ //pte++;
+ la += PAGE_SIZE;
+ pa += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+ while ((size > 0) && !superpage_aligned(la));
+ }
+ }
+ while ((size > 0) && !pd_aligned(la));
+ }
+ while ((size > 0) && !pdp_aligned(la));
+ }
+}
+
+void
+base_paging_init(l4_uint64_t phys_mem_max)
+{
+ ptab_alloc(&base_pml4_pa);
+
+ // Establish one-to-one mappings for the physical memory
+ pdir_map_range(base_pml4_pa, 0, 0, phys_mem_max,
+ INTEL_PDE_VALID | INTEL_PDE_WRITE | INTEL_PDE_USER);
+
+ //dbf_tss.cr3 = base_pml4_pa;
+
+ // XXX Turn on paging and activate long mode
+ paging_enable(base_pml4_pa);
+}
+
+void trap_dump_panic(const struct trap_state *st);
+void trap_dump_panic(const struct trap_state *st)
+{
+ int from_user = st->cs & 3;
+ int i;
+
+ printf("EAX %08x EBX %08x ECX %08x EDX %08x\n",
+ st->eax, st->ebx, st->ecx, st->edx);
+ printf("ESI %08x EDI %08x EBP %08x ESP %08x\n",
+ st->esi, st->edi, st->ebp,
+ from_user ? st->esp : (l4_uint32_t)&st->esp);
+ printf("EIP %08x EFLAGS %08x\n", st->eip, st->eflags);
+ printf("CS %04x SS %04x DS %04x ES %04x FS %04x GS %04x\n",
+ st->cs & 0xffff, from_user ? st->ss & 0xffff : get_ss(),
+ st->ds & 0xffff, st->es & 0xffff,
+ st->fs & 0xffff, st->gs & 0xffff);
+ printf("trapno %d, error %08x, from %s mode\n",
+ st->trapno, st->err, from_user ? "user" : "kernel");
+
+ if (st->trapno == 0x0d)
+ {
+ if (st->err & 1)
+ printf("(external event");
+ else
+ printf("(internal event");
+ if (st->err & 2)
+ printf(" regarding IDT gate descriptor no. 0x%02x)\n", st->err >> 3);
+ else
+ printf(" regarding %s entry no. 0x%02x)\n",
+ st->err & 4 ? "LDT" : "GDT", st->err >> 3);
+ }
+ else if (st->trapno == 0x0e)
+ printf("page fault linear address %08x\n", st->cr2);
+
+ if (!from_user)
+ for (i = 0; i < 32; i++)
+ printf("%08x%c", (&st->esp)[i], ((i & 7) == 7) ? '\n' : ' ');
+
+ panic("Unexpected trap while booting Fiasco!");
+}
+
+static void
+handle_dbf(void)
+{
+ /*
+ printf("\n"
+ "EAX %08x EBX %08x ECX %08x EDX %08x\n"
+ "ESI %08x EDI %08x EBP %08x ESP %08x\n"
+ "EIP %08x EFLAGS %08x\n"
+ "CS %04x SS %04x DS %04x ES %04x FS %04x GS %04x\n\n",
+ base_tss.eax, base_tss.ebx, base_tss.ecx, base_tss.edx,
+ base_tss.esi, base_tss.edi, base_tss.ebp, base_tss.esp,
+ base_tss.eip, base_tss.eflags,
+ base_tss.cs & 0xffff, base_tss.ss & 0xffff, base_tss.ds & 0xffff,
+ base_tss.es & 0xffff, base_tss.fs & 0xffff, base_tss.gs & 0xffff);
+ */
+ panic("Unexpected DOUBLE FAULT while booting Fiasco!");
+}
--- /dev/null
+/*
+ * (c) 2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ * Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#ifndef BOOT_CPU_H
+#define BOOT_CPU_H
+
+#include "types.h"
+
+void base_paging_init (l4_uint64_t);
+void base_cpu_setup (void);
+
+extern struct ptab64_mem_info_t ptab64_mem_info;
+
+#endif
--- /dev/null
+/*
+ * (c) 2009 Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#define GATE_INITTAB_BEGIN(name) \
+ .text 1 ;\
+ .globl name ;\
+name: ;\
+ .text
+
+#define GATE_ENTRY(n,entry,type) \
+ .text 1 ;\
+ .long entry ;\
+ .word n ;\
+ .word type ;\
+ .text
+
+#define GATE_INITTAB_END \
+ .text 1 ;\
+ .long 0 ;\
+ .text
+
+#define EXCEPTION(n,name) \
+ GATE_ENTRY(n,name,0x0e) ;\
+name: ;\
+ pushl $(0) ;\
+ pushl $(n) ;\
+ jmp alltraps
+
+#define EXCEP_USR(n,name) \
+ GATE_ENTRY(n,name,0x6e) ;\
+name: ;\
+ pushl $(0) ;\
+ pushl $(n) ;\
+ jmp alltraps
+
+#define EXCEP_ERR(n,name) \
+ GATE_ENTRY(n,name,0x0e) ;\
+name: ;\
+ pushl $(n) ;\
+ jmp alltraps
+
+
+GATE_INITTAB_BEGIN(boot_idt_inittab)
+
+EXCEPTION(0x00,t_zero_div)
+EXCEPTION(0x01,t_debug)
+EXCEPTION(0x02,t_nmi)
+EXCEP_USR(0x03,t_int3)
+EXCEP_USR(0x04,t_into)
+EXCEP_USR(0x05,t_bounds)
+EXCEPTION(0x06,t_invop)
+EXCEPTION(0x07,t_nofpu)
+GATE_ENTRY(0x08,0x20,0x05)
+EXCEPTION(0x09,a_fpu_over)
+EXCEP_ERR(0x0a,a_inv_tss)
+EXCEP_ERR(0x0b,t_segnp)
+EXCEP_ERR(0x0c,t_stack_fault)
+EXCEP_ERR(0x0d,t_gen_prot)
+EXCEP_ERR(0x0e,t_page_fault)
+EXCEPTION(0x0f,t_trap_0f)
+EXCEPTION(0x10,t_fpu_err)
+EXCEPTION(0x11,t_trap_11)
+EXCEPTION(0x12,t_trap_12)
+EXCEPTION(0x13,t_trap_13)
+EXCEPTION(0x14,t_trap_14)
+EXCEPTION(0x15,t_trap_15)
+EXCEPTION(0x16,t_trap_16)
+EXCEPTION(0x17,t_trap_17)
+EXCEPTION(0x18,t_trap_18)
+EXCEPTION(0x19,t_trap_19)
+EXCEPTION(0x1a,t_trap_1a)
+EXCEPTION(0x1b,t_trap_1b)
+EXCEPTION(0x1c,t_trap_1c)
+EXCEPTION(0x1d,t_trap_1d)
+EXCEPTION(0x1e,t_trap_1e)
+EXCEPTION(0x1f,t_trap_1f)
+
+GATE_INITTAB_END
+
+alltraps:
+ pusha
+ pushl %ds
+ pushl %es
+ pushl %fs
+ pushl %gs
+
+ movl %ss,%eax
+ movl %eax,%ds
+ movl %eax,%es
+ movl %esp,%eax
+ pushl %eax
+ call trap_dump_panic
+
--- /dev/null
+/*
+ * (c) 2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ * Alexander Warg <warg@os.inf.tu-dresden.de>,
+ * Frank Mehnert <fm3@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#include <stdio.h>
+#include <l4/util/mb_info.h>
+#include "boot_cpu.h"
+#include "boot_paging.h"
+#include "load_elf.h"
+
+extern void _exit(int rc);
+
+extern unsigned KERNEL_CS_64;
+extern char _binary_bootstrap64_bin_start;
+
+static l4_uint64_t find_upper_mem(l4util_mb_info_t *mbi)
+{
+ l4_uint64_t max = 0;
+ l4util_mb_addr_range_t *mmap;
+ l4util_mb_for_each_mmap_entry(mmap, mbi)
+ {
+ if (max < mmap->addr + mmap->size)
+ max = mmap->addr + mmap->size;
+ }
+ return max;
+}
+
+static void check_mbi_modules_in_limit(l4util_mb_info_t *mbi,
+ unsigned long long limit)
+{
+ l4util_mb_mod_t *mb_mod = (l4util_mb_mod_t *)(unsigned long)mbi->mods_addr;
+ unsigned i;
+ for (i = 0; i < mbi->mods_count; ++i)
+ if (mb_mod[i].mod_end >= limit)
+ {
+ printf("Multiboot module outside of supported initial memory size.\n");
+ printf("mod%d: end=%x >= limit=%llx\n", i, mb_mod[i].mod_end, limit);
+ printf("Please adapt your boot process\n"
+ " or supply more memory to bootstrap's allocator.\n");
+ while (1);
+ _exit(-1);
+ }
+}
+
+void bootstrap (l4util_mb_info_t *mbi, unsigned int flag, char *rm_pointer);
+void
+bootstrap (l4util_mb_info_t *mbi, unsigned int flag, char *rm_pointer)
+{
+ l4_uint32_t vma_start, vma_end;
+ struct
+ {
+ l4_uint32_t start;
+ l4_uint16_t cs __attribute__((packed));
+ } far_ptr;
+ l4_uint64_t mem_upper;
+
+ // setup stuff for base_paging_init()
+ base_cpu_setup();
+
+#ifdef REALMODE_LOADING
+ mem_upper = *(unsigned long*)(rm_pointer + 0x1e0);
+ mem_upper = 1024 * (1024 + mem_upper);
+#else
+ mem_upper = find_upper_mem(mbi);
+ if (!mem_upper)
+ mem_upper = 1024 * (1024 + mbi->mem_upper);
+#endif
+
+ printf("Highest physical memory address found: %llx (%llxMiB)\n",
+ mem_upper, mem_upper >> 20);
+
+ // our memory available for our initial identity mapped page table is
+ // enough to cover 4GB of physical memory that must contain anything that
+ // is required to boot, i.e. bootstrap, all modules, any required devices
+ // and the final location of sigma0 and moe
+ const unsigned long long Max_initial_mem = 4ull << 30;
+
+ check_mbi_modules_in_limit(mbi, Max_initial_mem);
+
+ if (mem_upper > Max_initial_mem)
+ mem_upper = Max_initial_mem;
+
+ // now do base_paging_init(): sets up paging with one-to-one mapping
+ base_paging_init(round_superpage(mem_upper));
+
+ printf("Loading 64bit part...\n");
+ // switch from 32 Bit compatibility mode to 64 Bit mode
+ far_ptr.cs = KERNEL_CS_64;
+ far_ptr.start = load_elf(&_binary_bootstrap64_bin_start,
+ &vma_start, &vma_end);
+
+ asm volatile("ljmp *(%4)"
+ :: "D"(mbi), "S"(flag), "d"(rm_pointer),
+ "c"(&ptab64_mem_info),
+ "r"(&far_ptr), "m"(far_ptr));
+}
--- /dev/null
+/*
+ * (c) 2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ * Frank Mehnert <fm3@os.inf.tu-dresden.de>,
+ * Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#ifndef BOOT_PAGING_H
+#define BOOT_PAGING_H
+
+#include "types.h"
+
+enum
+{
+ PAGE_SIZE = (1 << 12),
+ PAGE_MASK = (PAGE_SIZE - 1),
+ SUPERPAGE_SIZE = (1 << 21),
+ SUPERPAGE_MASK = (SUPERPAGE_SIZE - 1),
+ PD_SIZE = (1 << 30),
+ PD_MASK = (PD_SIZE - 1),
+ PDP_SIZE = (1LL << 39),
+ PDP_MASK = (PDP_SIZE - 1),
+};
+
+static inline int
+superpage_aligned(l4_uint32_t x)
+{ return (x & SUPERPAGE_MASK) == 0; }
+
+static inline int
+pd_aligned(l4_uint32_t x)
+{ return (x & PD_MASK) == 0; }
+
+static inline int
+pdp_aligned(l4_uint32_t x)
+{ return (x & PDP_MASK) == 0; }
+
+static inline l4_uint64_t round_superpage(l4_uint64_t x)
+{ return (x + SUPERPAGE_MASK) & ~SUPERPAGE_MASK; }
+
+#endif
--- /dev/null
+ENTRY(_start)
+SECTIONS
+{
+ . = 0x01000000;
+ _image_start = .;
+ .text :
+ {
+ *(.text .text.*)
+ *(.rodata .rodata.*)
+ } =0x9090
+
+ .data :
+ {
+ *(.data .data.*)
+ *(.bss .bss.*)
+ *(COMMON)
+ }
+ _image_end = .;
+
+ /* Value of DEFAULT_RELOC_amd64 */
+ .sixtyfour 0x2d0000 :
+ {
+ . = . + 500000;
+ }
+
+ /DISCARD/ : {
+ *(.interp)
+ *(.comment)
+ *(.note)
+ *(.eh_frame)
+ }
+}
--- /dev/null
+/*
+ * (c) 2009 Alexander Warg <warg@os.inf.tu-dresden.de>,
+ * Frank Mehnert <fm3@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#include <stdio.h>
+#include <string.h>
+
+#include "types.h"
+#include <l4/util/elf.h>
+#include "load_elf.h"
+
+extern char _image_start;
+extern char _image_end;
+
+static void check_overlap(unsigned long s, unsigned long e)
+{
+ if ( (unsigned long)&_image_end >= s
+ && (unsigned long)&_image_start <= e)
+ {
+ printf("Overwrite: ELF-PH: %lx - %lx, bootstrap loader: %lx - %lx\n",
+ s, e, (unsigned long)&_image_start, (unsigned long)&_image_end);
+ printf("Change your 'modaddr' setting.\n");
+ while (1)
+ ;
+ }
+}
+
+l4_uint32_t
+load_elf (void *elf, l4_uint32_t *vma_start, l4_uint32_t *vma_end)
+{
+ char *_elf = (char *) elf;
+ Elf64_Ehdr *eh = (Elf64_Ehdr *)(_elf);
+ Elf64_Phdr *ph = (Elf64_Phdr *)(_elf + eh->e_phoff);
+ l4_uint32_t _vma_start = ~0, _vma_end = 0;
+ int i;
+
+ for (i = 0; i < eh->e_phnum; i++, ph++)
+ {
+ if (ph->p_type != PT_LOAD)
+ continue;
+
+ if (ph->p_vaddr < _vma_start)
+ _vma_start = ph->p_vaddr;
+
+ if (ph->p_vaddr + ph->p_memsz > _vma_end)
+ _vma_end = ph->p_vaddr + ph->p_memsz;
+
+ check_overlap(ph->p_paddr, ph->p_paddr + ph->p_filesz);
+
+ memcpy((void*)((Elf32_Addr)ph->p_paddr),
+ _elf + ph->p_offset, ph->p_filesz);
+
+ if (ph->p_filesz < ph->p_memsz)
+ {
+ check_overlap(ph->p_paddr + ph->p_filesz, ph->p_paddr + ph->p_memsz);
+ memset((void*)((Elf32_Addr)(ph->p_paddr + ph->p_filesz)), 0,
+ ph->p_memsz - ph->p_filesz);
+ }
+ }
+
+ if (vma_start)
+ *vma_start = _vma_start;
+ if (vma_end)
+ *vma_end = _vma_end;
+
+ return eh->e_entry;
+}
--- /dev/null
+/*
+ * (c) 2009 Frank Mehnert <fm3@os.inf.tu-dresden.de>,
+ * Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#ifndef LOAD_ELF_H__
+#define LOAD_ELF_H__ 1
+
+#include "types.h"
+
+typedef void (*Startup_func)(void);
+
+l4_uint32_t load_elf(void *addr, l4_uint32_t *vma_start, l4_uint32_t *vma_end);
+
+#endif
--- /dev/null
+/*
+ * (c) 2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ * Frank Mehnert <fm3@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <l4/util/port_io.h>
+#include <l4/util/reboot.h>
+
+//#include "version.h"
+
+extern int hercules; /* provided by startup.c */
+
+static void direct_cons_putchar(unsigned char c, int to_hercules);
+static int direct_cons_try_getchar(void);
+ int have_hercules(void);
+ void reboot(void);
+
+int __libc_backend_outs( const char *s, size_t len);
+int __getchar(void);
+
+static void porte9(unsigned char c)
+{
+ l4util_out8(c, 0xe9);
+ if (c == 10)
+ l4util_out8(13, 0xe9);
+}
+
+int
+__libc_backend_outs( const char *s, size_t len)
+{
+ size_t i;
+ for (i = 0; i < len; i++)
+ {
+ direct_cons_putchar(s[i], 0);
+ if (0)
+ porte9(s[i]);
+ }
+
+ return 1;
+}
+
+void __attribute__((noreturn))
+reboot(void)
+{
+ l4util_out8(0x80, 0x70);
+ l4util_iodelay();
+ l4util_in8(0x71);
+ l4util_iodelay();
+
+ while (l4util_in8(0x64) & 0x02)
+ ;
+
+ l4util_out8(0x8F, 0x70);
+ l4util_iodelay();
+ l4util_out8(0x00, 0x71);
+ l4util_iodelay();
+
+ l4util_out8(0xFE, 0x64);
+ l4util_iodelay();
+
+ for (;;)
+ ;
+}
+
+int
+__getchar(void)
+{
+ int c = 0;
+ do
+ {
+ if (c == -1)
+ c = direct_cons_try_getchar();
+ } while (c == -1);
+ return c;
+}
+
+void
+_exit(int fd)
+{
+ (void)fd;
+ printf("\n\033[1mReturn reboots...\033[m\n");
+ __getchar();
+ printf("Rebooting.\n");
+ reboot();
+}
+
+static void
+direct_cons_putchar(unsigned char c, int to_hercules)
+{
+ static int ofs = -1;
+ static int esc;
+ static int esc_val;
+ static int attr = 0x07;
+ unsigned char *vidbase = (unsigned char*)(to_hercules ? 0xb0000 : 0xb8000);
+
+
+ if (ofs < 0)
+ {
+ /* Called for the first time - initialize. */
+ ofs = 80*2*24;
+ direct_cons_putchar('\n', to_hercules);
+ }
+
+ switch (esc)
+ {
+ case 1:
+ if (c == '[')
+ {
+ esc++;
+ goto done;
+ }
+ esc = 0;
+ break;
+
+ case 2:
+ if (c >= '0' && c <= '9')
+ {
+ esc_val = 10*esc_val + c - '0';
+ goto done;
+ }
+ if (c == 'm')
+ {
+ attr = esc_val ? 0x0f : 0x07;
+ goto done;
+ }
+ esc = 0;
+ break;
+ }
+
+ switch (c)
+ {
+ case '\n':
+ memcpy(vidbase, vidbase+80*2, 80*2*24);
+ memset(vidbase+80*2*24, 0, 80*2);
+ /* fall through... */
+ case '\r':
+ ofs = 0;
+ break;
+
+ case '\t':
+ ofs = (ofs + 8) & ~7;
+ break;
+
+ case '\033':
+ esc = 1;
+ esc_val = 0;
+ break;
+
+ default:
+ /* Wrap if we reach the end of a line. */
+ if (ofs >= 80)
+ direct_cons_putchar('\n', to_hercules);
+
+ /* Stuff the character into the video buffer. */
+ {
+ volatile unsigned char *p = vidbase + 80*2*24 + ofs*2;
+ p[0] = c;
+ p[1] = attr;
+ ofs++;
+ }
+ break;
+ }
+
+done:
+ return;
+}
+
+int
+have_hercules(void)
+{
+ unsigned short *p, p_save;
+ int count = 0;
+ unsigned long delay;
+
+ /* check for video memory */
+ p = (unsigned short*)0xb0000;
+ p_save = *p;
+ *p = 0xaa55; if (*p == 0xaa55) count++;
+ *p = 0x55aa; if (*p == 0x55aa) count++;
+ *p = p_save;
+ if (count != 2)
+ return 0;
+
+ /* check for I/O ports (HW cursor) */
+ l4util_out8(0x0f, 0x3b4);
+ l4util_iodelay();
+ l4util_out8(0x66, 0x3b5);
+ for (delay=0; delay<0x100000UL; delay++)
+ asm volatile ("nop" : :);
+ if (l4util_in8(0x3b5) != 0x66)
+ return 0;
+
+ l4util_iodelay();
+ l4util_out8(0x0f, 0x3b4);
+ l4util_iodelay();
+ l4util_out8(0x99, 0x3b5);
+
+ for (delay=0; delay<0x10000; delay++)
+ l4util_iodelay();
+ if (l4util_in8(0x3b5) != 0x99)
+ return 0;
+
+ /* reset position */
+ l4util_out8(0xf, 0x3b4);
+ l4util_iodelay();
+ l4util_out8(0x0, 0x3b5);
+ l4util_iodelay();
+ return 1;
+}
+
+#define SHIFT -1
+
+static const char keymap[128][2] = {
+ {0}, /* 0 */
+ {27, 27}, /* 1 - ESC */
+ {'1', '!'}, /* 2 */
+ {'2', '@'},
+ {'3', '#'},
+ {'4', '$'},
+ {'5', '%'},
+ {'6', '^'},
+ {'7', '&'},
+ {'8', '*'},
+ {'9', '('},
+ {'0', ')'},
+ {'-', '_'},
+ {'=', '+'},
+ {8, 8}, /* 14 - Backspace */
+ {'\t','\t'}, /* 15 */
+ {'q', 'Q'},
+ {'w', 'W'},
+ {'e', 'E'},
+ {'r', 'R'},
+ {'t', 'T'},
+ {'y', 'Y'},
+ {'u', 'U'},
+ {'i', 'I'},
+ {'o', 'O'},
+ {'p', 'P'},
+ {'[', '{'},
+// {']','}'}, /* 27 */
+ {'+', '*'}, /* 27 */
+ {'\r','\r'}, /* 28 - Enter */
+ {0, 0}, /* 29 - Ctrl */
+ {'a', 'A'}, /* 30 */
+ {'s', 'S'},
+ {'d', 'D'},
+ {'f', 'F'},
+ {'g', 'G'},
+ {'h', 'H'},
+ {'j', 'J'},
+ {'k', 'K'},
+ {'l', 'L'},
+ {';', ':'},
+ {'\'','"'}, /* 40 */
+ {'`', '~'}, /* 41 */
+ {SHIFT, SHIFT}, /* 42 - Left Shift */
+ {'\\', '|'}, /* 43 */
+ {'z', 'Z'}, /* 44 */
+ {'x', 'X'},
+ {'c', 'C'},
+ {'v', 'V'},
+ {'b', 'B'},
+ {'n', 'N'},
+ {'m', 'M'},
+ {',', '<'},
+ {'.', '>'},
+ // {'/','?'}, /* 53 */
+ {'-', '_'}, /* 53 */
+ {SHIFT, SHIFT}, /* 54 - Right Shift */
+ {0, 0}, /* 55 - Print Screen */
+ {0, 0}, /* 56 - Alt */
+ {' ', ' '}, /* 57 - Space bar */
+ {0, 0}, /* 58 - Caps Lock */
+ {0, 0}, /* 59 - F1 */
+ {0, 0}, /* 60 - F2 */
+ {0, 0}, /* 61 - F3 */
+ {0, 0}, /* 62 - F4 */
+ {0, 0}, /* 63 - F5 */
+ {0, 0}, /* 64 - F6 */
+ {0, 0}, /* 65 - F7 */
+ {0, 0}, /* 66 - F8 */
+ {0, 0}, /* 67 - F9 */
+ {0, 0}, /* 68 - F10 */
+ {0, 0}, /* 69 - Num Lock */
+ {0, 0}, /* 70 - Scroll Lock */
+ {'7', '7'}, /* 71 - Numeric keypad 7 */
+ {'8', '8'}, /* 72 - Numeric keypad 8 */
+ {'9', '9'}, /* 73 - Numeric keypad 9 */
+ {'-', '-'}, /* 74 - Numeric keypad '-' */
+ {'4', '4'}, /* 75 - Numeric keypad 4 */
+ {'5', '5'}, /* 76 - Numeric keypad 5 */
+ {'6', '6'}, /* 77 - Numeric keypad 6 */
+ {'+', '+'}, /* 78 - Numeric keypad '+' */
+ {'1', '1'}, /* 79 - Numeric keypad 1 */
+ {'2', '2'}, /* 80 - Numeric keypad 2 */
+ {'3', '3'}, /* 81 - Numeric keypad 3 */
+ {'0', '0'}, /* 82 - Numeric keypad 0 */
+ {'.', '.'}, /* 83 - Numeric keypad '.' */
+};
+
+int
+direct_cons_try_getchar(void)
+{
+ static unsigned shift_state;
+ unsigned status, scan_code, ch;
+
+retry:
+ __asm__ __volatile__ ("rep; nop");
+
+ /* Wait until a scan code is ready and read it. */
+ status = l4util_in8(0x64);
+ if ((status & 0x01) == 0)
+ {
+ return -1;
+ }
+ scan_code = l4util_in8(0x60);
+
+ /* Drop mouse events */
+ if ((status & 0x20) != 0)
+ {
+ return -1;
+ }
+
+ /* Handle key releases - only release of SHIFT is important. */
+ if (scan_code & 0x80)
+ {
+ scan_code &= 0x7f;
+ if (keymap[scan_code][0] == SHIFT)
+ shift_state = 0;
+ goto retry;
+ }
+
+ /* Translate the character through the keymap. */
+ ch = keymap[scan_code][shift_state];
+ if (ch == (unsigned)SHIFT)
+ {
+ shift_state = 1;
+ goto retry;
+ } else if (ch == 0)
+ goto retry;
+
+ return ch;
+}
--- /dev/null
+/*
+ * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ * Frank Mehnert <fm3@os.inf.tu-dresden.de>,
+ * Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#include <l4/sys/compiler.h>
+
+ .section .init
+
+ .globl _start
+_start:
+#if defined(REALMODE_LOADING) && !defined(IMAGE_MODE)
+ cld
+ cli
+ mov $(3 * 8), %eax
+ mov %eax, %ds
+ mov %eax, %es
+ mov %eax, %fs
+ mov %eax, %gs
+
+ lss _stack_seg, %esp
+#else
+#ifdef __PIC__
+ lea _stack(%rip),%esp
+#else
+ lea _stack,%esp
+#endif
+#endif
+
+#ifdef __PIC__
+ push $_exit@plt
+ jmp __main@plt
+#else
+ push $_exit
+ jmp __main
+#endif
+
+
+ /* MultiBoot header - see multiboot.h. */
+ .p2align(2)
+
+_mb_header:
+ .long 0x1BADB002 /* magic */
+ .long 0 /* flags: AOUT_KLUDGE */
+ .long 0 - 0x1BADB002
+
+#if defined(REALMODE_LOADING) && !defined(IMAGE_MODE)
+_stack_seg:
+ .long _stack
+ .word (3 * 8)
+#endif
+
+ .bss
+
+ .globl _stack
+ .space 8192
+_stack:
--- /dev/null
+PKGDIR ?= ../../../..
+L4DIR ?= $(PKGDIR)/../..
+
+TARGET = libc32.a
+
+SYSTEMS = amd64
+
+
+SRC_C = __assert_fail.c __lltostr.c __ltostr.c __v_printf.c \
+ isspace.c memcpy.c memmove.c memset.c printf.c puts.c \
+ strtol.c strtoul.c vprintf.c
+
+include $(L4DIR)/mk/lib.mk
+
+CFLAGS := $(filter-out $(CCXX_FLAGS) $(CARCHFLAGS), $(CFLAGS)) -mno-sse
+CPPFLAGS := -nostdinc -I$(SRC_DIR)/include -m32
+OPTS := -Os
--- /dev/null
+#include "assert.h"
+#include "stdio.h"
+#include "stdlib.h"
+
+extern void _exit(int rc);
+
+void
+__assert_fail (const char *__assertion, const char *__file,
+ unsigned int __line)
+{
+ printf("ASSERTION_FAILED (%s)\n"
+ " in file %s:%d\n", __assertion, __file, __line);
+ _exit (EXIT_FAILURE);
+}
+
+extern __typeof(__assert_fail) __assert
+ __attribute__((weak, alias("__assert_fail")));
--- /dev/null
+#include <string.h>
+//#include <moddiv.h>
+
+int __lltostr(char *s, int size, unsigned long long i, int base, char UpCase);
+
+int __lltostr(char *s, int size, unsigned long long i, int base, char UpCase)
+{
+ char *tmp;
+ unsigned int j=0;
+ //_moddiv_t r;
+
+ s[--size]=0;
+
+ tmp=s+size;
+
+ if ((base==0)||(base>36)) base=10;
+
+ j=0;
+ if (!i)
+ {
+ *(--tmp)='0';
+ j=1;
+ }
+
+ while((tmp>s)&&(i))
+ {
+ tmp--;
+ // r = moddiv(i,base);
+ if ((*tmp=i%base+'0')>'9') *tmp+=(UpCase?'A':'a')-'9'-1;
+ i=i/base;
+ j++;
+ }
+ memmove(s,tmp,j+1);
+
+ return j;
+}
--- /dev/null
+#include <string.h>
+#include <stdlib.h>
+//#include <moddiv.h>
+
+int __ltostr(char *s, unsigned int size, unsigned long i, unsigned int base, int UpCase)
+{
+ char *tmp;
+ unsigned int j=0;
+ //_moddiv_t r;
+
+ s[--size]=0;
+
+ tmp=s+size;
+
+ if ((base==0)||(base>36)) base=10;
+
+ j=0;
+ if (!i)
+ {
+ *(--tmp)='0';
+ j=1;
+ }
+
+ while((tmp>s)&&(i))
+ {
+ tmp--;
+ //r = moddiv(i,base);
+ if ((*tmp=i%base+'0')>'9') *tmp+=(UpCase?'A':'a')-'9'-1;
+ i=i/base;
+ j++;
+ }
+ memmove(s,tmp,j+1);
+
+ return j;
+}
--- /dev/null
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "vprintf_backend.h"
+
+static inline unsigned int skip_to(const char *format) {
+ int unsigned nr;
+ for (nr=0; format[nr] && (format[nr]!='%'); ++nr);
+ return nr;
+}
+
+#define A_WRITE(fn,buf,sz) ((fn)->put((buf),(sz),(fn)->data))
+
+static char* pad_line[16]= { " ", "0000000000000000", };
+static inline int write_pad(struct output_op* fn, int len, int padwith) {
+ int nr=0;
+ for (;len>15;len-=16,nr+=16) {
+ A_WRITE(fn,pad_line[(padwith=='0')?1:0],16);
+ }
+ if (len>0) {
+ A_WRITE(fn,pad_line[(padwith=='0')?1:0],(unsigned int)len); nr+=len;
+ }
+ return nr;
+}
+
+int __v_printf(struct output_op* fn, const char *format, va_list arg_ptr)
+{
+ int len=0;
+
+ while (*format) {
+ unsigned int sz = skip_to(format);
+ if (sz) {
+ A_WRITE(fn,format,sz); len+=sz;
+ format+=sz;
+ }
+ if (*format=='%') {
+ char buf[128];
+
+ char ch, padwith=' ';
+ char *s;
+
+ char flag_in_sign=0;
+ char flag_upcase=0;
+ char flag_hash=0;
+ char flag_left=0;
+ char flag_space=0;
+ char flag_sign=0;
+ char flag_dot=0;
+ signed char flag_long=0;
+
+ unsigned int base;
+ unsigned int width=0, preci=0;
+
+ long int number=0;
+ long long llnumber=0;
+
+ ++format;
+inn_printf:
+ switch(ch=*format++) {
+ case 0:
+ return -1;
+ break;
+
+ /* FLAGS */
+ case '#':
+ flag_hash=1;
+ goto inn_printf;
+
+ case 'h':
+ --flag_long;
+ goto inn_printf;
+ case 'l':
+ ++flag_long;
+ goto inn_printf;
+
+ case '0':
+ padwith='0';
+ goto inn_printf;
+
+ case '-':
+ flag_left=1;
+ goto inn_printf;
+
+ case ' ':
+ flag_space=1;
+ goto inn_printf;
+
+ case '+':
+ flag_sign=1;
+ goto inn_printf;
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if(flag_dot) return -1;
+ width=strtoul(format-1,&s,10);
+ format=s;
+ goto inn_printf;
+
+ case '*':
+ width=va_arg(arg_ptr,int);
+ goto inn_printf;
+
+ case '.':
+ flag_dot=1;
+ if (*format=='*') {
+ preci=va_arg(arg_ptr,int);
+ ++format;
+ } else {
+ long int tmp=strtol(format,&s,10);
+ preci=tmp<0?0:tmp;
+ format=s;
+ }
+ goto inn_printf;
+
+ /* print a char or % */
+ case 'c':
+ ch=(char)va_arg(arg_ptr,int);
+ case '%':
+ A_WRITE(fn,&ch,1); ++len;
+ break;
+
+ /* print a string */
+ case 's':
+ s=va_arg(arg_ptr,char *);
+ if (!s) s="(null)";
+ sz = strlen(s);
+ if (flag_dot && sz>preci) sz=preci;
+
+print_out:
+ if (width && (!flag_left)) {
+ len+=write_pad(fn,(signed int)width-(signed int)sz,padwith);
+ }
+ A_WRITE(fn,s,sz); len+=sz;
+ if (width && (flag_left)) {
+ len+=write_pad(fn,(signed int)width-(signed int)sz,' ');
+ }
+ break;
+
+ /* print an integer value */
+ case 'b':
+ base=2;
+ sz=0;
+ goto num_printf;
+ case 'p':
+ flag_hash=1;
+ if(sizeof(void*)>sizeof(unsigned))
+ ++flag_long;
+ if(sizeof(void*)>sizeof(long))
+ ++flag_long;
+ ch='x';
+ case 'X':
+ flag_upcase=(ch=='X');
+ case 'x':
+ base=16;
+ sz=0;
+ if (flag_hash) {
+ buf[1]='0';
+ buf[2]=ch;
+ sz=2;
+ }
+ goto num_printf;
+ case 'd':
+ case 'i':
+ flag_in_sign=1;
+ case 'u':
+ base=10;
+ sz=0;
+ goto num_printf;
+ case 'o':
+ base=8;
+ sz=0;
+ if (flag_hash) {
+ buf[1]='0';
+ ++sz;
+ }
+
+num_printf:
+ if (flag_long>0) {
+ if (flag_long>1)
+ llnumber=va_arg(arg_ptr,long long);
+ else
+ number=va_arg(arg_ptr,long);
+ }
+ else
+ number=va_arg(arg_ptr,int);
+
+ if (flag_in_sign) {
+ if ((flag_long>1)&&(llnumber<0)) {
+ llnumber=-llnumber;
+ flag_in_sign=2;
+ } else
+ if (number<0) {
+ number=-number;
+ flag_in_sign=2;
+ }
+ }
+ if (flag_long<0) number&=0xffff;
+ if (flag_long<-1) number&=0xff;
+ if (flag_long>1)
+ sz += __lltostr(buf+1+sz,sizeof(buf)-5,(unsigned long long) llnumber,base,flag_upcase);
+ else
+ sz += __ltostr(buf+1+sz,sizeof(buf)-5,(unsigned long) number,base,flag_upcase);
+
+ s=buf+1;
+
+ if (flag_in_sign==2) {
+ *(--s)='-';
+ ++sz;
+ } else if ((flag_in_sign)&&(flag_sign || flag_space)) {
+ *(--s)=(flag_sign)?'+':' ';
+ ++sz;
+ }
+
+ goto print_out;
+
+ default:
+ break;
+ }
+ }
+ }
+ return len;
+}
+
--- /dev/null
+#ifndef _ASSERT_H
+#define _ASSERT_H
+
+#include <cdefs.h>
+
+__BEGIN_DECLS
+/* This prints an "Assertion failed" message and aborts. */
+void __assert_fail (const char *__assertion, const char *__file,
+ unsigned int __line)
+ __attribute__ ((__noreturn__));
+
+__END_DECLS
+
+#if (__GNUC__>=3)
+# define ASSERT_EXPECT_FALSE(exp) __builtin_expect((exp), 0)
+#else
+# define ASSERT_EXPECT_FALSE(exp) (exp)
+#endif
+
+/* We don't show information about the current function since needs
+ * additional space -- especially with gcc-2.95. The function name
+ * can be found by searching the EIP in the kernel image. */
+#undef assert
+#ifdef NDEBUG
+#define assert(expr)
+#define check(expr) (void)(expr)
+#else
+# define assert(expr) \
+ ((void) ((ASSERT_EXPECT_FALSE(!(expr))) \
+ ? (__assert_fail (#expr, __FILE__, __LINE__), 0) \
+ : 0))
+# define check(expr) assert(expr)
+#endif
+
+#endif
--- /dev/null
+#ifndef __CDEFS_H__
+#define __CDEFS_H__
+
+#ifndef __cplusplus
+#define __BEGIN_DECLS
+#define __END_DECLS
+#else
+#define __BEGIN_DECLS extern "C" {
+#define __END_DECLS }
+#endif
+
+
+#endif // __CDEFS_H__
--- /dev/null
+#ifndef _CTYPE_H
+#define _CTYPE_H
+
+#include <cdefs.h>
+
+__BEGIN_DECLS
+
+int isascii (int c) __attribute__ ((__const__));
+int isblank (int c) __attribute__ ((__const__));
+int isalnum (int c) __attribute__ ((__const__));
+int isalpha (int c) __attribute__ ((__const__));
+int isdigit (int c) __attribute__ ((__const__));
+int isspace (int c) __attribute__ ((__const__));
+
+int isupper (int c) __attribute__ ((__const__));
+int islower (int c) __attribute__ ((__const__));
+
+int tolower(int c) __attribute__ ((__const__));
+int toupper(int c) __attribute__ ((__const__));
+
+int isprint(int c) __attribute__ ((__const__));
+int ispunct(int c) __attribute__ ((__const__));
+int iscntrl(int c) __attribute__ ((__const__));
+
+/* fscking GNU extensions! */
+int isxdigit(int c) __attribute__ ((__const__));
+
+int isgraph(int c) __attribute__ ((__const__));
+
+__END_DECLS
+
+#endif
--- /dev/null
+/* */
+
+
+
+/* This file defines the backend interface */
+/* of the kernel c-library. */
+
+#ifndef __LIBC_BACKEND_H__
+#define __LIBC_BACKEND_H__
+
+#include <stddef.h>
+#include <cdefs.h>
+
+__BEGIN_DECLS
+
+/**
+ * The text output backend.
+ *
+ * This function must be provided to the c-library for
+ * text output. It must simply send len characters of s
+ * to an output device.
+ *
+ * @param s the string to send (not zero terminated).
+ * @param len the number of characters.
+ * @return 1 on success, 0 else.
+ */
+int __libc_backend_outs( const char *s, size_t len );
+
+
+/**
+ * The text input backend.
+ *
+ * This function must be provided to the c-library for
+ * text input. It has to block til len characters are
+ * read or a newline is reached. The retrurn value gives
+ * the number of characters virtually read.
+ *
+ * @param s a poiznter to the buffer for the read text.
+ * @param len the size of the buffer.
+ * @return the number of characters virtually read.
+ */
+int __libc_backend_ins( char *s, size_t len );
+
+__END_DECLS
+
+
+#endif //__LIBC_BACKEND_H__
--- /dev/null
+#ifndef MLC_MEMCPY_H__
+#define MLC_MEMCPY_H__
+
+#include <cdefs.h>
+#include <stddef.h>
+
+__BEGIN_DECLS
+
+void *memcpy(void *dest, const void *src, size_t n);
+
+__END_DECLS
+
+#endif // MLC_MEMCPY_H__
+
--- /dev/null
+#ifndef PANIC_H
+#define PANIC_H
+
+#include <cdefs.h>
+
+__BEGIN_DECLS
+
+void panic (const char *format, ...) __attribute__ ((__noreturn__));
+
+__END_DECLS
+
+#endif
--- /dev/null
+#if defined(__sparc__) || defined(__alpha__)
+enum {
+ __no_type_class = -1,
+ __void_type_class,
+ __integer_type_class,
+ __char_type_class,
+ __enumeral_type_class,
+ __boolean_type_class,
+ __pointer_type_class,
+ __reference_type_class,
+ __offset_type_class,
+ __real_type_class,
+ __complex_type_class,
+ __function_type_class,
+ __method_type_class,
+ __record_type_class,
+ __union_type_class,
+ __array_type_class,
+ __string_type_class,
+ __set_type_class,
+ __file_type_class,
+ __lang_type_class
+};
+#endif
+
+#if defined(__sparc__)
+
+typedef char* va_list;
+#define va_end(ap) ap=0
+
+#define va_start(AP, LASTARG) \
+ (__builtin_next_arg (LASTARG), AP = (char *) __builtin_saveregs ())
+
+#define __va_rounded_size(TYPE) \
+ (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))
+
+/* We don't declare the union member `d' to have type TYPE
+ because that would lose in C++ if TYPE has a constructor. */
+/* We cast to void * and then to TYPE * because this avoids
+ a warning about increasing the alignment requirement.
+ The casts to char * avoid warnings about invalid pointer arithmetic. */
+#define va_arg(pvar,TYPE) \
+__extension__ \
+(*({((__builtin_classify_type (*(TYPE*) 0) >= __record_type_class \
+ || (__builtin_classify_type (*(TYPE*) 0) == __real_type_class \
+ && sizeof (TYPE) == 16)) \
+ ? ((pvar) = (char *)(pvar) + __va_rounded_size (TYPE *), \
+ *(TYPE **) (void *) ((char *)(pvar) - __va_rounded_size (TYPE *))) \
+ : __va_rounded_size (TYPE) == 8 \
+ ? ({ union {char __d[sizeof (TYPE)]; int __i[2];} __u; \
+ __u.__i[0] = ((int *) (void *) (pvar))[0]; \
+ __u.__i[1] = ((int *) (void *) (pvar))[1]; \
+ (pvar) = (char *)(pvar) + 8; \
+ (TYPE *) (void *) __u.__d; }) \
+ : ((pvar) = (char *)(pvar) + __va_rounded_size (TYPE), \
+ ((TYPE *) (void *) ((char *)(pvar) - __va_rounded_size (TYPE)))));}))
+
+
+#elif defined(__mips__)
+
+typedef char * va_list;
+
+#ifdef __mips64
+#define __va_rounded_size(__TYPE) \
+ (((sizeof (__TYPE) + 8 - 1) / 8) * 8)
+#else
+#define __va_rounded_size(__TYPE) \
+ (((sizeof (__TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))
+#endif
+#ifdef __mips64
+#define __va_reg_size 8
+#else
+#define __va_reg_size 4
+#endif
+
+#define va_start(__AP, __LASTARG) \
+ (__AP = (va_list) __builtin_next_arg (__LASTARG))
+
+#ifdef __mips64
+#ifdef __MIPSEB__
+#define va_arg(__AP, __type) \
+ ((__type *) (void *) (__AP = (char *) \
+ ((((__PTRDIFF_TYPE__)__AP + 8 - 1) & -8) \
+ + __va_rounded_size (__type))))[-1]
+#else
+#define va_arg(__AP, __type) \
+ ((__AP = (char *) ((((__PTRDIFF_TYPE__)__AP + 8 - 1) & -8) \
+ + __va_rounded_size (__type))), \
+ *(__type *) (void *) (__AP - __va_rounded_size (__type)))
+#endif
+
+#else /* not __mips64 */
+
+#ifdef __MIPSEB__
+/* For big-endian machines. */
+#define va_arg(__AP, __type) \
+ ((__AP = (char *) ((__alignof__ (__type) > 4 \
+ ? ((__PTRDIFF_TYPE__)__AP + 8 - 1) & -8 \
+ : ((__PTRDIFF_TYPE__)__AP + 4 - 1) & -4) \
+ + __va_rounded_size (__type))), \
+ *(__type *) (void *) (__AP - __va_rounded_size (__type)))
+#else
+/* For little-endian machines. */
+#define va_arg(__AP, __type) \
+ ((__type *) (void *) (__AP = (char *) ((__alignof__(__type) > 4 \
+ ? ((__PTRDIFF_TYPE__)__AP + 8 - 1) & -8 \
+ : ((__PTRDIFF_TYPE__)__AP + 4 - 1) & -4) \
+ + __va_rounded_size(__type))))[-1]
+#endif
+#endif
+
+#elif defined(__powerpc__)
+
+typedef struct __va_list_tag {
+ unsigned char gpr; /* index into the array of 8 GPRs stored in the
+ register save area gpr=0 corresponds to r3,
+ gpr=1 to r4, etc. */
+ unsigned char fpr; /* index into the array of 8 FPRs stored in the
+ register save area fpr=0 corresponds to f1,
+ fpr=1 to f2, etc. */
+ char *overflow_arg_area; /* location on stack that holds the next
+ overflow argument */
+ char *reg_save_area; /* where r3:r10 and f1:f8, if saved are stored */
+} va_list[1];
+
+#define __va_overflow(AP) (AP)->overflow_arg_area
+#ifdef __OPTIMIZE__
+extern void __va_arg_type_violation(void) __attribute__((__noreturn__));
+#else
+#define __va_arg_type_violation()
+#endif
+
+typedef struct {
+ long __gp_save[8]; /* save area for GP registers */
+ double __fp_save[8]; /* save area for FP registers */
+} __va_regsave_t;
+
+/* Macros to access the register save area */
+/* We cast to void * and then to TYPE * because this avoids
+ a warning about increasing the alignment requirement. */
+#define __VA_FP_REGSAVE(AP,OFS,TYPE) \
+ ((TYPE *) (void *) (&(((__va_regsave_t *) \
+ (AP)->reg_save_area)->__fp_save[OFS])))
+
+#define __VA_GP_REGSAVE(AP,OFS,TYPE) \
+ ((TYPE *) (void *) (&(((__va_regsave_t *) \
+ (AP)->reg_save_area)->__gp_save[OFS])))
+
+#define __va_start_common(AP, FAKE) \
+ __builtin_memcpy ((AP), __builtin_saveregs (), sizeof(va_list))
+
+#define va_start(AP,LASTARG) \
+ (__builtin_next_arg (LASTARG), __va_start_common (AP, 0))
+
+#ifdef _SOFT_FLOAT
+#define __va_float_p(TYPE) 0
+#else
+#define __va_float_p(TYPE) (__builtin_classify_type(*(TYPE *)0) == 8)
+#endif
+
+#define __va_aggregate_p(TYPE) (__builtin_classify_type(*(TYPE *)0) >= 12)
+#define __va_size(TYPE) ((sizeof(TYPE) + sizeof (long) - 1) / sizeof (long))
+
+#define va_arg(AP,TYPE) \
+__extension__ (*({ \
+ register TYPE *__ptr; \
+ \
+ if (__va_float_p (TYPE) && sizeof (TYPE) < 16) \
+ { \
+ unsigned char __fpr = (AP)->fpr; \
+ if (__fpr < 8) \
+ { \
+ __ptr = __VA_FP_REGSAVE (AP, __fpr, TYPE); \
+ (AP)->fpr = __fpr + 1; \
+ } \
+ else if (sizeof (TYPE) == 8) \
+ { \
+ unsigned long __addr = (unsigned long) (__va_overflow (AP)); \
+ __ptr = (TYPE *)((__addr + 7) & -8); \
+ __va_overflow (AP) = (char *)(__ptr + 1); \
+ } \
+ else \
+ { \
+ /* float is promoted to double. */ \
+ __va_arg_type_violation (); \
+ } \
+ } \
+ \
+ /* Aggregates and long doubles are passed by reference. */ \
+ else if (__va_aggregate_p (TYPE) || __va_float_p (TYPE)) \
+ { \
+ unsigned char __gpr = (AP)->gpr; \
+ if (__gpr < 8) \
+ { \
+ __ptr = * __VA_GP_REGSAVE (AP, __gpr, TYPE *); \
+ (AP)->gpr = __gpr + 1; \
+ } \
+ else \
+ { \
+ TYPE **__pptr = (TYPE **) (__va_overflow (AP)); \
+ __ptr = * __pptr; \
+ __va_overflow (AP) = (char *) (__pptr + 1); \
+ } \
+ } \
+ \
+ /* Only integrals remaining. */ \
+ else \
+ { \
+ /* longlong is aligned. */ \
+ if (sizeof (TYPE) == 8) \
+ { \
+ unsigned char __gpr = (AP)->gpr; \
+ if (__gpr < 7) \
+ { \
+ __gpr += __gpr & 1; \
+ __ptr = __VA_GP_REGSAVE (AP, __gpr, TYPE); \
+ (AP)->gpr = __gpr + 2; \
+ } \
+ else \
+ { \
+ unsigned long __addr = (unsigned long) (__va_overflow (AP)); \
+ __ptr = (TYPE *)((__addr + 7) & -8); \
+ (AP)->gpr = 8; \
+ __va_overflow (AP) = (char *)(__ptr + 1); \
+ } \
+ } \
+ else if (sizeof (TYPE) == 4) \
+ { \
+ unsigned char __gpr = (AP)->gpr; \
+ if (__gpr < 8) \
+ { \
+ __ptr = __VA_GP_REGSAVE (AP, __gpr, TYPE); \
+ (AP)->gpr = __gpr + 1; \
+ } \
+ else \
+ { \
+ __ptr = (TYPE *) __va_overflow (AP); \
+ __va_overflow (AP) = (char *)(__ptr + 1); \
+ } \
+ } \
+ else \
+ { \
+ /* Everything else was promoted to int. */ \
+ __va_arg_type_violation (); \
+ } \
+ } \
+ __ptr; \
+}))
+
+#define va_end(AP) ((void)0)
+
+/* Copy va_list into another variable of this type. */
+#define __va_copy(dest, src) *(dest) = *(src)
+
+#elif defined(__alpha__)
+
+typedef struct {
+ char *__base; /* Pointer to first integer register. */
+ int __offset; /* Byte offset of args so far. */
+} va_list;
+
+#define va_start(pvar, firstarg) \
+ (__builtin_next_arg (firstarg), \
+ (pvar) = *(va_list *) __builtin_saveregs ())
+#define va_end(__va) ((void) 0)
+
+#define __va_tsize(__type) \
+ (((sizeof (__type) + __extension__ sizeof (long long) - 1) \
+ / __extension__ sizeof (long long)) * __extension__ sizeof (long long))
+
+#define va_arg(__va, __type) \
+(*(((__va).__offset += __va_tsize (__type)), \
+ (__type *)(void *)((__va).__base + (__va).__offset \
+ - (((__builtin_classify_type (* (__type *) 0) \
+ == __real_type_class) && (__va).__offset <= (6 * 8)) \
+ ? (6 * 8) + 8 : __va_tsize (__type)))))
+
+#else /* !__sparc__ && !__powerpc__ && !__mips__ && !__alpha__*/
+
+typedef char* va_list;
+
+/* this only works when everything is passed on the stack (i.e. x86) */
+#if __WORDSIZE == 64
+#define va_start(ap,argn) ap=((char*)&argn)+8
+#else
+#define va_start(ap,argn) ap=((char*)&argn)+4
+#endif
+#define va_arg(ap,type) (ap+=sizeof(type), *(type*)((char*)((void*)ap)-sizeof(type)))
+
+#endif
+
+#ifndef __va_copy
+#define __va_copy(x,y) x=y
+#endif
+
+#ifndef va_end
+#define va_end(ap) ((void)0)
+#endif
+
--- /dev/null
+#ifndef _STDARG_H
+#define _STDARG_H
+
+
+
+#ifdef __GNUC__
+#if (__GNUC__ > 2) || (__GNUC__ == 2) && (__GNUC_MINOR__ > 96)
+
+typedef __builtin_va_list va_list;
+#define va_start(v,l) __builtin_va_start((v),(l))
+#define va_end __builtin_va_end
+#define va_arg __builtin_va_arg
+#define __va_copy(d,s) __builtin_va_copy((d),(s))
+
+#endif
+#endif
+
+#ifndef va_end
+#include <stdarg-cruft.h>
+#endif
+
+#if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L
+#define va_copy(d,s) __va_copy(d,s)
+#endif
+
+#endif
--- /dev/null
+
+#ifndef _STDDEF_H
+#define _STDDEF_H
+
+typedef unsigned size_t;
+
+#endif
--- /dev/null
+#ifndef _STDIO_H
+#define _STDIO_H
+
+#include <cdefs.h>
+#include <stddef.h>
+
+__BEGIN_DECLS
+
+int putchar(int c);
+int puts(const char *s);
+int printf(const char *format, ...) __attribute__((format(printf,1,2)));
+int sprintf(char *str, const char *format, ...) __attribute__((format(printf,2,3)));
+int snprintf(char *str, size_t size, const char *format, ...) __attribute__((format(printf,3,4)));
+int asprintf(char **ptr, const char* format, ...) __attribute__((format(printf,2,3)));
+
+#if 0
+int scanf(const char *format, ...) __attribute__((format(scanf,1,2)));
+int sscanf(const char *str, const char *format, ...) __attribute__((format(scanf,2,3)));
+#endif
+
+#include <stdarg.h>
+
+int vprintf(const char *format, va_list ap) __attribute__((format(printf,1,0)));
+int vsprintf(char *str, const char *format, va_list ap) __attribute__((format(printf,2,0)));
+int vsnprintf(char *str, size_t size, const char *format, va_list ap) __attribute__((format(printf,3,0)));
+
+
+typedef int FILE;
+
+int vscanf(const char *format, va_list ap) __attribute__((format(scanf,1,0)));
+int vsscanf(const char *str, const char *format, va_list ap) __attribute__((format(scanf,2,0)));
+
+int sscanf(const char *str, const char *format, ...);
+
+__END_DECLS
+
+#endif
--- /dev/null
+#ifndef _STDLIB_H
+#define _STDLIB_H
+
+#include <cdefs.h>
+#include <stddef.h>
+
+__BEGIN_DECLS
+
+int atexit(void (*function)(void));
+
+double strtod(const char *nptr, char **endptr);
+long int strtol(const char *nptr, char **endptr, int base);
+unsigned long int strtoul(const char *nptr, char **endptr, int base);
+
+extern int __ltostr(char *s, unsigned int size, unsigned long i, unsigned int base, int UpCase);
+extern int __dtostr(double d,char *buf,unsigned int maxlen,unsigned int prec);
+
+#ifndef __STRICT_ANSI__
+__extension__ long long int strtoll(const char *nptr, char **endptr, int base);
+__extension__ unsigned long long int strtoull(const char *nptr, char **endptr, int base);
+__extension__ int __lltostr(char *s, unsigned int size, unsigned long long i, unsigned int base, int UpCase);
+#endif
+
+int atoi(const char *nptr);
+long int atol(const char *nptr);
+double atof(const char *nptr);
+
+#define EXIT_FAILURE 1
+#define EXIT_SUCCESS 0
+
+void exit(int status) __attribute__((noreturn));
+void abort(void);
+
+/* warning: the rand() implementation of the diet libc really sucks. */
+#define RAND_MAX 32767
+
+typedef struct { int quot,rem; } div_t;
+div_t div(int numer, int denom) __attribute__((const));
+
+typedef struct { long int quot,rem; } ldiv_t;
+ldiv_t ldiv(long int numer, long int denom) __attribute__((const));
+
+typedef struct { long long int quot,rem; } lldiv_t;
+lldiv_t lldiv(long long int numer, long long int denom) __attribute__((const));
+
+int abs(int i) __attribute__((const));
+long int labs(long int i) __attribute__((const));
+__extension__ long long int llabs(long long int i) __attribute__((const));
+
+__END_DECLS
+
+#endif
--- /dev/null
+#ifndef _STRING_H
+#define _STRING_H
+
+#include <cdefs.h>
+#include <stddef.h>
+
+#include <memcpy.h>
+
+__BEGIN_DECLS
+
+char *strcpy(char *dest, const char *src);
+char *strncpy(char *dest, const char *src, size_t n);
+
+void *memccpy(void *dest, const void *src, int c, size_t n);
+void *memmove(void *dest, const void *src, size_t n);
+
+int memccmp(const void *s1, const void *s2, int c, size_t n);
+int memcmp(const void *s1, const void *s2, size_t n);
+int strcmp(const char *s1, const char *s2);
+int strncmp(const char *s1, const char *s2, size_t n);
+
+int strcasecmp(const char *s1, const char *s2);
+int strncasecmp(const char *s1, const char *s2, size_t n);
+
+#if (__GNUC__>=3)
+size_t strlen(const char *s) __attribute__((pure));
+#else
+size_t strlen(const char *s);
+#endif
+
+char *strstr(const char *haystack, const char *needle);
+
+char *strdup(const char *s);
+
+char *strchr(const char *s, int c);
+char *strrchr(const char *s, int c);
+
+char *strcat(char *dest, const char *src);
+char *strncat(char *dest, const char *src, size_t n);
+
+size_t strspn(const char *s, const char *_accept);
+size_t strcspn(const char *s, const char *reject);
+
+char *strpbrk(const char *s, const char *_accept);
+char *strsep(char **stringp, const char *delim);
+
+void* memset(void *s, int c, size_t n);
+void* memchr(const void *s, int c, size_t n);
+
+int strcoll(const char *s1, const char *s2);
+
+
+__END_DECLS
+
+
+#endif
--- /dev/null
+#warning "your code included obsolescent <strings.h>. Please change that to <string.h>!"
+#include <string.h>
--- /dev/null
+#include <ctype.h>
+
+int __isspace_ascii ( int ch );
+int __isspace_ascii ( int ch )
+{
+ return (unsigned int)(ch - 9) < 5u || ch == ' ';
+}
+
+int isspace ( int ch ) __attribute__((weak,alias("__isspace_ascii")));
--- /dev/null
+#include <stddef.h>
+#include <string.h>
+
+void* memcpy(void* dst, const void* src, size_t count) {
+ register char *d=dst;
+ register const char *s=src;
+ ++count; /* this actually produces better code than using count-- */
+ while (--count) {
+ *d = *s;
+ ++d; ++s;
+ }
+ return dst;
+}
--- /dev/null
+#define _POSIX_SOURCE
+#define _XOPEN_SOURCE
+#include <stddef.h>
+#include <string.h>
+
+void *memmove(void *dst, const void *src, size_t count)
+{
+ char *a = dst;
+ const char *b = src;
+ if (src!=dst)
+ {
+ if (src>dst)
+ {
+ while (count--) *a++ = *b++;
+ }
+ else
+ {
+ a+=count-1;
+ b+=count-1;
+ while (count--) *a-- = *b--;
+ }
+ }
+ return dst;
+}
--- /dev/null
+#include <stddef.h>
+#include <string.h>
+
+void * memset(void * dst, int s, size_t count) {
+ register char * a = dst;
+ count++; /* this actually creates smaller code than using count-- */
+ while (--count)
+ *a++ = s;
+ return dst;
+}
--- /dev/null
+#include <stdarg.h>
+#include <stdio.h>
+
+int printf (const char *format, ...) {
+
+ int n;
+ va_list args;
+
+ va_start (args, format);
+ n = vprintf (format, args);
+ va_end (args);
+
+ return n;
+}
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include "libc_backend.h"
+
+size_t strlen(const char *s)
+{
+ size_t l = 0;
+ while (*s)
+ {
+ l++;
+ s++;
+ }
+ return l;
+}
+
+
+int puts(const char *c)
+{
+ __libc_backend_outs(c, strlen(c));
+ return __libc_backend_outs("\n", 1);
+}
--- /dev/null
+#include <ctype.h>
+#include <stdlib.h>
+
+#define ABS_LONG_MIN 2147483648UL
+
+long int strtol (const char *nptr, char **endptr, int base) {
+
+ int neg = 0;
+ unsigned long int v;
+
+ while (isspace (*nptr))
+ nptr++;
+
+ if (*nptr == '-') {
+ neg = -1;
+ ++nptr;
+ }
+
+ v = strtoul (nptr, endptr, base);
+
+ if (v >= ABS_LONG_MIN) {
+ if (v == ABS_LONG_MIN && neg) {
+ return v;
+ }
+ return 0; //(neg ? LONG_MIN : LONG_MAX);
+ }
+
+ return (neg ? -v : v);
+}
--- /dev/null
+#include <ctype.h>
+#include <stdlib.h>
+
+unsigned long int strtoul (const char *nptr, char **endptr, int base) {
+
+ unsigned long int v=0;
+
+ while(isspace(*nptr)) ++nptr;
+ if (*nptr == '+') ++nptr;
+ if (base==16 && nptr[0]=='0') goto skip0x;
+ if (!base) {
+ if (*nptr=='0') {
+ base=8;
+skip0x:
+ if (nptr[1]=='x'||nptr[1]=='X') {
+ nptr+=2;
+ base=16;
+ }
+ } else
+ base=10;
+ }
+ while(*nptr) {
+ register unsigned char c=*nptr;
+ c=(c>='a'?c-'a'+10:c>='A'?c-'A'+10:c<='9'?c-'0':0xff);
+ if (c>=base) break;
+ {
+ register unsigned long int w=v << 4;/*=v*base*/;
+ if(base==8) w = v << 3;
+ //if(base==16) w = v << 4;
+ if(base==10) w = (v << 3) + (v << 1);
+ if (w<v) {
+ return (unsigned long)-1;
+ }
+ v=w+c;
+ }
+ ++nptr;
+ }
+ if (endptr) *endptr=(char *)nptr;
+ return v;
+}
--- /dev/null
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "vprintf_backend.h"
+#include "libc_backend.h"
+
+
+
+int vprintf(const char *format, va_list ap)
+{
+ struct output_op _ap = { 0, (output_func*) &__libc_backend_outs };
+ return __v_printf(&_ap,format,ap);
+}
--- /dev/null
+#ifndef __VPRINTF_BACKEND_H__
+#define __VPRINTF_BACKEND_H__
+
+#include <stddef.h>
+#include <cdefs.h>
+
+typedef int (output_func)(char const *, size_t, void*);
+
+struct output_op {
+ void *data;
+ output_func *put;
+};
+
+__BEGIN_DECLS
+
+int __v_printf(struct output_op* fn, const char *format, va_list arg_ptr);
+
+__END_DECLS
+
+
+#endif // __VPRINTF_BACKEND_H__
--- /dev/null
+/*
+ * (c) 2008-2009 Frank Mehnert <fm3@os.inf.tu-dresden.de>,
+ * Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#ifndef __ARCH_AMD64_MACROS_H__
+#define __ARCH_AMD64_MACROS_H__
+
+/* We need this typecasts since addresses of the GRUB multiboot info
+ * have always a size of 32 Bit. */
+
+#define L4_CHAR_PTR(x) (char*)(l4_addr_t)(x)
+#define L4_CONST_CHAR_PTR(x) (const char*)(l4_addr_t)(x)
+#define L4_VOID_PTR(x) (void*)(l4_addr_t)(x)
+#define L4_MB_MOD_PTR(x) (l4util_mb_mod_t*)(l4_addr_t)(x)
+
+#endif /* ! __ARCH_AMD64_MACROS_H__ */
--- /dev/null
+/*
+ * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ * Alexander Warg <warg@os.inf.tu-dresden.de>,
+ * Frank Mehnert <fm3@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include "ldscript.inc"
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm",
+ "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+
+PHDRS {
+ common PT_LOAD;
+#ifndef SINGLE_SECTION
+ mods PT_LOAD;
+#endif
+}
+
+/* Some explanation for SINGLE_SECTION thing: For bootstrap we want to have
+ * a single program header only because some boot-loaders require that.
+ * Unfortunately it does not seem to be possible to have the following
+ * order:
+ * text - data - bss - modules
+ * because bss is smaller in the binary than unpacked and things get screwed
+ * up. So what we do it the following:
+ * text - data_including_bss - modules
+ * This way things seem to work and we only have one program header.
+ */
+
+SECTIONS
+{
+ /* Read-only sections, merged into text segment. The start address of
+ * the text segment is : */
+ . = LINKADDR;
+ .text :
+ {
+ _stext = .;
+ *(.text.init)
+ *(.init)
+ *(.text .text.* .gnu.linkonce.t.*)
+ *(.glue_7t) *(.glue_7)
+ KEEP (*(.fini))
+ LONG(0xc3) /* terminate .fini */
+ . = ALIGN(0x40);
+ *(.rodata .rodata.* .gnu.linkonce.r.* .rodata1)
+ } : common
+
+ _etext = .;
+ PROVIDE (etext = .);
+
+ /* ensure that data starts at a new L4 page */
+ . = ALIGN(4096);
+ .data :
+ {
+ *(.data .data.* .gnu.linkonce.d.*)
+ *(.anno)
+
+ CTORS
+ PLATFORMS
+
+ . = ALIGN(4);
+ _module_info_start = .;
+ *(.module_info)
+ _module_info_end = .;
+
+#ifndef SINGLE_SECTION
+ } : common
+
+ /* exception frames for C++ */
+ .eh_frame :
+ {
+#endif
+ KEEP (*(.eh_frame))
+ LONG(0) /* terminate .eh_frame */
+#ifndef SINGLE_SECTION
+ } : common
+#endif
+
+ . = ALIGN(4);
+ _edata = .;
+ PROVIDE (edata = .);
+
+ _bss_start = .;
+#ifndef SINGLE_SECTION
+ .bss :
+ {
+#endif
+ *(.dynbss)
+ *(.bss .gnu.linkonce.b.*)
+ *(COMMON)
+ } : common
+ _bss_end = .;
+ _end = . ;
+ PROVIDE (end = .);
+
+/* Only move modules to modaddr if bootstrap is being loaded by an elf
+ * loader, and we do not need to copy images around at runtime (e.g. with
+ * compression) */
+#if defined(PLACE_MODULES_AT_MODADDR) && !defined(SINGLE_SECTION)
+ . = RAM_BASE + MODADDR;
+#endif
+ . = ALIGN(4096);
+ .data.m :
+ {
+ . = ALIGN(4096);
+ _module_data_start = .;
+ *(EXCLUDE_FILE (*mod00.bin *mod01.bin *mod02.bin) .module_data)
+ *(.module_data)
+ _module_data_end = .;
+#ifndef SINGLE_SECTION
+ } : mods
+#else
+ } : common
+#endif
+
+ /* Moved here to ensure that these sections are located _after_ the text
+ * section. In the other case we would get program sections with a virtual
+ * address of 0 */
+ .hash : { *(.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .rel.dyn : { *(.rel.dyn) }
+
+ /* drop the following sections since we do not need them for DROPS */
+ /DISCARD/ : {
+ *(.interp)
+ *(.comment)
+ *(.note)
+ *(.stab)
+ *(.fini)
+ *(.ARM.exidx*)
+ }
+}
+
--- /dev/null
+/*
+ * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ * Frank Mehnert <fm3@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+/* -*- c -*- */
+
+#define MIMIC_A_VMLINUZ
+
+.section .text.init,#alloc,#execinstr
+.type _start,#function
+.globl _start
+_start:
+/* Some bootloaders like it this way, for others it won't harm */
+#ifdef MIMIC_A_VMLINUZ
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ b 10f
+ .word 0x016f2818
+ .word _start
+ .word _module_data_end
+10:
+#endif
+ /*
+ * It might be the case that we're not run at the position where we
+ * have been linked to. If this is the case we copy ourselves to the
+ * position we're linked to.
+ */
+ adr r4, run /* Running version */
+ ldr r5, .LCrun /* supposed to be version */
+ cmp r4, r5 /* If equal ... */
+ beq run /* ... go to run */
+
+ /* Disable caches as we're moving code around */
+ mcr p15, 0, r3, c7, c5, 0 /* ICIALLU */
+ mrc p15, 0, r0, c1, c0
+ bic r0, #0x0004
+ bic r0, #0x1000
+ mcr p15, 0, r0, c1, c0
+
+ /* Figure how to move */
+ ldr r7, .LCend_bin
+ subs r8, r5, r4 /* r8 is the distance between the blocks */
+ bpl move_behind
+
+ /* Copy before, copy forwards */
+ /* First, copy our copy loop to the very beginning to avoid code
+ * overwrites */
+ mov r9, r5 /* r9: run address */
+ ldr r0, .LCstart_bin
+ ldr r3, 3f
+ str r3, [r0], #4
+ ldr r3, 32f
+ str r3, [r0], #4
+ ldr r3, 33f
+ str r3, [r0], #4
+ ldr r3, 34f
+ str r3, [r0], #4
+ ldr r3, 35f
+ str r3, [r0], #4
+ ldr pc, .LCstart_bin
+
+3: ldr r6, [r4], #4
+32: str r6, [r5], #4
+33: cmp r5, r7
+34: blt 3b
+35: mov pc, r9
+
+ /* Copy behind, copy backwards */
+move_behind:
+ sub r8, r7, r8 /* r8 points to the end of source image */
+3: ldr r6, [r8, #-4]! /* Take bytes */
+ str r6, [r7, #-4]! /* Put bytes */
+ cmp r5, r7
+ blt 3b
+ ldr pc, .LCrun
+
+
+.LCrun: .word run
+.LCstart_bin: .word _start
+.LCend_bin: .word _module_data_end
+
+run:
+ mov r3, #0x1000
+ sub r3, r3, #1 /* r3 == 0xfff */
+ mrc p15, 0, r0, c0, c0, 0 /* Main ID */
+ lsr r0, #4
+ and r0, r0, r3
+
+ /* Check for processors that understand CPU ID */
+ mov r9, #0xb00
+ orr r9, #0x002
+ cmp r0, r9
+ beq do_cpuid
+
+ mov r3, #0xc00
+ orr r9, r3, #0x00f
+ cmp r0, r9
+ beq do_cpuid
+
+ orr r9, r3, #0x007
+ cmp r0, r9
+ beq do_cpuid
+
+ orr r9, r3, #0x009
+ cmp r0, r9
+ bne do_bootstrap /* None matched, normal startup */
+
+do_cpuid:
+ mrc p15, 0, r0, c0, c0, 5 /* CPU ID */
+ and r0, r0, #0xf /* CPU id */
+ cmp r0, #0 /* CPU0 continues with bootstrap */
+ beq do_bootstrap
+
+/* CPU1+ wait for bootup */
+
+ // I-cache on
+ mrc p15, 0, r0, c1, c0, 0
+ orr r0, r0, #(1 << 12)
+ mcr p15, 0, r0, c1, c0, 0
+
+ // IRQs off, SVC
+ mrs r0, cpsr
+ orr r0, #0xd3
+ msr cpsr_c, r0
+
+#if defined(PLATFORM_TYPE_rv) || defined(PLATFORM_TYPE_rv_pbx) || \
+ defined(PLATFORM_TYPE_rv_vexpress) || defined(PLATFORM_TYPE_rv_vexpress_a15)
+
+ // enable GIC CPU interface + prio mask for IRQs
+ mrc p15, 0, r0, c0, c0, 0 // r0: cpu-id
+ and r0, r0, #0x70
+ cmp r0, #0x70
+
+ // get board ID and retrieve MPCore-base from table
+ movne r7, #0x10000000
+ moveq r7, #0x00010000
+ orreq r7, #0x1c000000
+ ldr r5, [r7]
+ bic r5, #0xff
+
+ adr r6, .Lboard_data_table
+2:
+ ldr r4, [r6]
+ cmp r4, #0
+ beq 3f
+ cmp r4, r5
+ bne 4f
+
+ ldr r3, [r6, #4]
+ cmp r0, r3
+ beq 3f
+ cmp r3, #0
+ beq 3f
+4: add r6, #12
+ b 2b
+
+3:
+ ldr r4, [r6, #8]
+ mov r0, #0x1
+ str r0, [r4, #0]
+ mov r0, #0xf0
+ str r0, [r4, #4]
+
+1:
+ ldr r6, [r7, #0x30]
+ cmp r6, #0
+ movne pc, r6
+ .inst 0xe320f003 /* wfi */
+ ldr r0, [r4, #12]
+ str r0, [r4, #16]
+ b 1b
+
+.Lboard_data_table:
+ /* VExpress */
+ .word 0x1190f500 /* Board ID */
+ .word 0x00000070 /* CPU ID */
+ .word 0x2c002000 /* MPCore base */
+
+ .word 0x1190f500 /* Board ID */
+ .word 0x00000000 /* CPU ID */
+ .word 0x1e000100 /* MPCore base */
+
+ /* Default value (with #0) must come last! */
+ /* Realview */
+ .word 0
+ .word 0
+ .word 0x1f000100
+
+#else
+1: .word 0xe320f003 /* wfi */
+ b 1b
+#endif
+
+do_bootstrap:
+ ldr r3, .LCcrt0_tramppage /* Load address of tramppage var */
+ str sp, [r3] /* Store SP in variable */
+ ldr sp, .LCstack
+
+ mov r0, r2 /* ATAG pointer */
+ bl __main
+1: b 1b
+
+.LCcrt0_tramppage: .word crt0_tramppage
+.LCstack: .word crt0_stack_high
+
+.section ".bss"
+
+ .global crt0_tramppage
+crt0_tramppage:
+ .space 4
+
+ .global crt0_stack_low
+ .align 3
+crt0_stack_low:
+ .space 8192
+ .global crt0_stack_high
+crt0_stack_high:
--- /dev/null
+#include "support.h"
+#include "startup.h"
+
+extern "C" int __aeabi_unwind_cpp_pr0(void);
+extern "C" int __aeabi_unwind_cpp_pr1(void);
+
+enum { _URC_FAILURE = 9 };
+int __aeabi_unwind_cpp_pr0(void) { return _URC_FAILURE; }
+int __aeabi_unwind_cpp_pr1(void) { return _URC_FAILURE; }
+
+extern "C" void __main();
+void __main()
+{
+ unsigned long r;
+
+ asm volatile("mrc p15, 0, %0, c1, c0, 0" : "=r" (r) : : "memory");
+ r &= ~1UL;
+ r |= 2; // alignment check on
+ asm volatile("mcr p15, 0, %0, c1, c0, 0" : : "r" (r) : "memory");
+
+ clear_bss();
+ ctor_init();
+ Platform_base::iterate_platforms();
+
+ startup(_mbi_cmdline);
+ while(1)
+ ;
+}
--- /dev/null
+/*
+ * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#include "ARCH-x86/macros.h"
--- /dev/null
+/*
+ * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU Lesser General Public License 2.1.
+ * Please see the COPYING-LGPL-2.1 file for details.
+ */
+
+#include "support.h"
+
+void
+reboot_arch(void) __attribute__((noreturn));
+
+void
+reboot_arch(void)
+{
+ Platform_base::platform->reboot();
+
+ while (1)
+ ;
+}
--- /dev/null
+
+#include "ldscript.inc"
+
+OUTPUT_FORMAT("elf32-powerpc", "elf32-big",
+ "elf32-little")
+ENTRY(_start)
+
+PHDRS {
+ text PT_LOAD;
+ data PT_LOAD;
+ mods PT_LOAD;
+}
+
+SECTIONS
+{
+ /* Read-only sections, merged into text segment. The start address of
+ * the text segment is : */
+ . = LINKADDR;
+ .text :
+ {
+ . = ALIGN(4);
+ _stext = .;
+ *(.text.init)
+ *(.init)
+ *(.text .text.* .gnu.linkonce.t.*)
+ *(.glue_7t) *(.glue_7)
+ KEEP (*(.fini))
+ LONG(0xc3) /* terminate .fini */
+ . = ALIGN(0x40);
+ *(.rodata .rodata.* .gnu.linkonce.r.* .rodata1)
+ } : text
+
+ _etext = .;
+ PROVIDE (etext = .);
+
+ /* ensure that data starts at a new L4 page */
+ . = ALIGN(4096);
+ .data :
+ {
+ *(.data .data.* .gnu.linkonce.d.*)
+ *(.anno)
+
+ CTORS
+ PLATFORMS
+
+ . = ALIGN(4);
+ _module_info_start = .;
+ *(.module_info)
+ _module_info_end = .;
+ } : data
+ /* exception frames for C++ */
+ .eh_frame :
+ {
+ KEEP (*(.eh_frame))
+ LONG(0) /* terminate .eh_frame */
+ } : data
+
+ . = ALIGN(4);
+ _edata = .;
+ PROVIDE (edata = .);
+
+ _bss_start = .;
+ .bss :
+ {
+ *(.dynbss)
+ *(.bss .gnu.linkonce.b.*)
+ *(COMMON)
+ } : data
+ _bss_end = .;
+ _end = . ;
+ PROVIDE (end = .);
+
+ /* Moved here to ensure that these sections are located _after_ the text
+ * section. In the other case we would get program sections with a virtual
+ * address of 0 */
+ .hash : { *(.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .rel.dyn : { *(.rel.dyn) }
+
+/* Only move modules to modaddr if bootstrap is being loaded by an elf
+ * loader, and we do not need to copy images around at runtime (e.g. with
+ * compression) */
+#if defined(PLACE_MODULES_AT_MODADDR) && !defined(SINGLE_SECTION)
+ . = MODADDR;
+#else
+ . = ALIGN(4096);
+#endif
+ _module_data_start = .;
+ .module_data : {
+ *(EXCLUDE_FILE (*mod00.bin *mod01.bin *mod02.bin) .module_data)
+ *(.module_data)
+ } : mods
+ _module_data_end = .;
+
+ /* drop the following sections since we do not need them for DROPS */
+ /DISCARD/ : {
+ *(.interp)
+ *(.comment)
+ *(.note)
+ *(.stab)
+ *(.stabstr*)
+ }
+}
+
--- /dev/null
+/*
+ * (c) 2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+/* -*- c -*- */
+
+.section .text.init, "ax"
+.type _start, @function
+.globl _start
+_start:
+ lis %r1, crt0_stack_high@ha /* load stack pointer */
+ addi %r1, %r1, crt0_stack_high@l
+ b __main
+1:
+ b 1b
+
+.section ".bss", "aw"
+
+.global crt0_stack_low
+crt0_stack_low:
+ .space 4096
+.global crt0_stack_high
+crt0_stack_high:
--- /dev/null
+#include "support.h"
+#include "startup.h"
+
+#include <l4/drivers/of.h>
+
+extern "C" void __main(unsigned long p1, unsigned long p2, unsigned long p3);
+void __main(unsigned long, unsigned long, unsigned long p3)
+{
+ clear_bss();
+ ctor_init();
+ L4_drivers::Of::set_prom(p3); //p3 is OF prom pointer
+ Platform_base::iterate_platforms();
+
+ printf("PPC platform initialized\n");
+ startup(_mbi_cmdline);
+ while(1)
+ ;
+}
--- /dev/null
+/*
+ * (c) 2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#include "init_kip.h"
+
+#include <l4/drivers/of_if.h>
+
+void
+init_kip_v2_arch(l4_kernel_info_t* l4i)
+{
+ L4_drivers::Of_if of_if;
+ //l4i->total_ram = of_if.detect_ramsize();
+ printf("TBD: set total RAM via mem-descs!\n");
+ l4i->frequency_cpu = (l4_uint32_t)of_if.detect_cpu_freq() / 1000; //kHz
+ l4i->frequency_bus = (l4_uint32_t)of_if.detect_bus_freq();
+
+ of_if.vesa_set_mode(0x117);
+}
--- /dev/null
+/*
+ * (c) 2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#include "ARCH-x86/macros.h"
--- /dev/null
+/*
+ * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU Lesser General Public License 2.1.
+ * Please see the COPYING-LGPL-2.1 file for details.
+ */
+
+void
+reboot_arch(void) __attribute__((noreturn));
+
+void
+reboot_arch(void)
+{
+ for (;;)
+ ;
+}
--- /dev/null
+
+#include "ldscript.inc"
+
+ENTRY(_start)
+
+PHDRS {
+ common PT_LOAD;
+#ifdef IMAGE_MODE
+ mods PT_LOAD;
+#endif
+}
+
+SECTIONS
+{
+ . = LINKADDR;
+ /* Merge .text, .rodata, and .data in one segment to save space */
+ .text :
+ {
+ _stext = .;
+ *(.init)
+ *(.text .text.* .gnu.linkonce.t.*)
+ } : common
+
+ .data :
+ {
+ *(.rodata* .gnu.linkonce.r.*)
+ . = ALIGN(8);
+ *(.data)
+ *(.data.*)
+
+ CTORS
+ PLATFORMS
+
+ _module_info_start = .;
+ *(.module_info)
+ _module_info_end = .;
+
+ } : common
+
+ _edata = .;
+ PROVIDE (edata = .);
+ . = ALIGN(4096);
+ _bss_start = .;
+ .bss :
+ {
+ *(.bss)
+ *(COMMON)
+ *(.bss_memmap)
+ } : common
+ _bss_end = .;
+ _end = . ;
+ PROVIDE (end = .);
+
+/* Only move modules to modaddr if bootstrap is being loaded by an elf
+ * loader, and we do not need to copy images around at runtime (e.g. with
+ * compression) */
+#ifdef IMAGE_MODE
+#if defined(PLACE_MODULES_AT_MODADDR) && !defined(SINGLE_SECTION)
+ . = RAM_BASE + MODADDR;
+#endif
+ _module_data_start = .;
+ .module_data : {
+ *(EXCLUDE_FILE (*mod00.bin *mod01.bin *mod02.bin) .module_data)
+ *(.module_data)
+ } : mods
+ _module_data_end = .;
+#endif
+
+ /DISCARD/ : {
+ *(.interp)
+ *(.comment)
+ *(.note)
+ *(.eh_frame)
+ *(.stab)
+ *(.stabstr)
+ *(.fini)
+ }
+}
--- /dev/null
+#define TRAP(H) mov %psr, %l0; sethi %hi(H), %l4; jmp %l4+%lo(H); nop;
+#define TRAP_ENTRY(H) rd %psr, %l0; b H; rd %wim, %l3; nop;
+#define TRAP_ENTRY_INTERRUPT(int_level) \
+ mov int_level, %l7; rd %psr, %l0; b _prom_leonbare_irq_entry; rd %wim, %l3;
+#define BAD_TRAP ta 0; nop; nop; nop;
+
+.section ".bss"
+.align(0x2000)
+ .global crt0_stack_low
+_stack:
+crt0_stack_low:
+.space 8192
+ .global crt0_stack_high
+crt0_stack_high:
+
+.text
+/*
+ * Trap handler table -> must be aligned to page size
+ * as specified by the SPARC v8 manual (p. 31).
+ */
+.globl _leon_traphandlers
+.align(0x1000)
+_leon_traphandlers:
+ BAD_TRAP
+ BAD_TRAP
+ BAD_TRAP
+ BAD_TRAP
+ BAD_TRAP
+ TRAP(sparc_window_overflow);
+ TRAP(sparc_window_underflow);
+ BAD_TRAP
+ BAD_TRAP
+ BAD_TRAP
+ BAD_TRAP
+ BAD_TRAP
+ BAD_TRAP
+ BAD_TRAP
+ BAD_TRAP
+ BAD_TRAP
+ BAD_TRAP
+
+.globl _start
+_start:
+
+ rd %asr17, %g1
+
+ /*
+ * setup trap handler table
+ */
+ sethi %hi(_leon_traphandlers), %g2
+ wr %g2, %tbr
+
+ /* the TBR setup above comes into effect three instructions from now!
+ * Right now, we assume that no trap occurs in between.
+ */
+
+ /* set stack pointer */
+ sethi %hi(_stack), %sp
+ or %sp, %lo(_stack), %sp
+
+ /*
+ * setup task with enough space for registers %l0-%l7 and %i0-%i7
+ */
+ sub %sp, 64, %sp
+
+ sethi %hi(_stack), %fp
+ or %fp, %lo(_stack), %fp
+
+ /* enable traps */
+ mov %psr, %l0
+ or %l0, (1 << 5), %l0
+ mov %l0, %psr
+
+ ba __main
+ nop
+
+ ta 0
+
+
+.globl sparc_window_overflow
+sparc_window_overflow:
+ mov %wim, %l3 /* need to determine new WIM */
+ mov %g1, %l7
+ srl %l3, 1, %g1
+
+ /*
+ * Find out if we are on LEON3 (PSR[24:27] == 3)
+ * or on LEON2. For LEON3, we can read the number of
+ * register windows from ASR17
+ */
+ mov %psr, %l4
+ srl %l4, 24, %l4
+ and %l4, 3, %l4
+ subcc %l4, 3, %g0
+ bne 1f
+ nop
+
+ /*
+ * It's a LEON3
+ */
+ mov %asr17, %l4
+
+ /* calculate new WIM */
+ and %l4, 0x1f, %l4
+ sll %l3, %l4, %l4
+ or %l4, %g1, %g1
+
+ /*
+ * The trick here is to move to a valid stack frame
+ * and store the register window contents there.
+ */
+ save
+ mov %g1, %wim
+ nop; nop; nop
+
+ std %l0, [%sp + 0];
+ std %l2, [%sp + 8];
+ std %l4, [%sp + 16];
+ std %l6, [%sp + 24];
+ std %i0, [%sp + 32];
+ std %i2, [%sp + 40];
+ std %i4, [%sp + 48];
+ std %i6, [%sp + 56];
+
+ restore
+ mov %l7, %g1
+ jmp %l1
+ rett %l2
+
+1: ta 0
+
+.globl sparc_window_underflow
+sparc_window_underflow:
+ mov %wim, %l3 /* need to determine new WIM */
+ sll %l3, 1, %l4
+
+ /* Determine LEON version */
+ mov %psr, %l5
+ srl %l5, 24, %l5
+ and %l5, 3, %l5
+ subcc %l5, 3, %g0
+ bne 1f
+ nop
+
+ mov %asr17, %l5
+ and %l5, 0x1f, %l5
+ srl %l3, %l5, %l5
+ or %l5, %l4, %l5
+ mov %l5, %wim
+ nop; nop; nop
+
+ restore ! Two restores to get into the
+ restore ! window to restore
+ ldd [%sp + 0], %l0; ! Restore window from the stack
+ ldd [%sp + 8], %l2;
+ ldd [%sp + 16], %l4;
+ ldd [%sp + 24], %l6;
+ ldd [%sp + 32], %i0;
+ ldd [%sp + 40], %i2;
+ ldd [%sp + 48], %i4;
+ ldd [%sp + 56], %i6;
+ save ! Get back to the trap window.
+ save
+
+ jmp %l1
+ rett %l2
+
+1: ta 0
--- /dev/null
+#include "support.h"
+#include "startup.h"
+
+extern "C" void __main();
+void __main()
+{
+ clear_bss();
+ ctor_init();
+ Platform_base::iterate_platforms();
+
+ startup(_mbi_cmdline);
+ while(1)
+ ;
+}
--- /dev/null
+#pragma once
+
+enum Leon_memory_map
+{
+ LEON_PROM_BASE = 0x00000000,
+ LEON_IO_BASE = 0x20000000,
+ LEON_RAM_BASE = 0x40000000,
+ LEON_AHB_BASE = 0x80000000,
+ LEON_ETH_BASE = 0xFFFB0000,
+ LEON_CAN_BASE = 0xFFFC0000,
+ LEON_PNP_BASE = 0xFFFFF000,
+};
+
+
+enum Leon_register_offsets
+{
+ LEON_MCTRL = 0,
+ LEON_APBUART = 0x100,
+ LEON_IRQMP = 0x200,
+ LEON_GPTIMER = 0x300,
+ LEON_PS2 = 0x500,
+ LEON_VGA = 0x600,
+ LEON_AHBUART = 0x700,
+ LEON_GRGPIO = 0x800,
+ LEON_GRSPW1 = 0xA00,
+ LEON_GRSPW2 = 0xB00,
+ LEON_GRSPW3 = 0xD00,
+ LEON_AHBSTAT = 0xF00,
+ LEON_AHBPNP = 0xFF000,
+};
+
+
+enum Leon_traps
+{
+ LEON_TR_RESET = 0x00,
+ LEON_TR_INSTR_ACCESS_ERR = 0x01,
+ LEON_TR_ILLEGAL_INSTR = 0x02,
+ LEON_TR_PRIV_INSTR = 0x03,
+ LEON_TR_FP_DISABLED = 0x04,
+ LEON_TR_WRITE_ERR = 0x2B,
+ LEON_TR_CP_DISABLED = 0x2f,
+ LEON_TR_WATCHPOINT = 0x0B,
+ LEON_TR_WINDOW_OVERFL = 0x05,
+ LEON_TR_WINDOW_UNDERFL = 0x06,
+ LEON_TR_REG_HW_ERR = 0x20,
+ LEON_TR_ALIGN = 0x07,
+ LEON_TR_FP_EXC = 0x08,
+ LEON_TR_CP_EXC = 0x28,
+ LEON_TR_DATA_ACCESS_EXC = 0x09,
+ LEON_TR_TAG_OVERFL = 0x0A,
+ LEON_TR_DIVIDE_EXC = 0x2A,
+ LEON_TR_IRQ1 = 0x11,
+ LEON_TR_IRQ2 = 0x12,
+ LEON_TR_IRQ3 = 0x13,
+ LEON_TR_IRQ4 = 0x14,
+ LEON_TR_IRQ5 = 0x15,
+ LEON_TR_IRQ6 = 0x16,
+ LEON_TR_IRQ7 = 0x17,
+ LEON_TR_IRQ8 = 0x18,
+ LEON_TR_IRQ9 = 0x19,
+ LEON_TR_IRQ10 = 0x1A,
+ LEON_TR_IRQ11 = 0x1B,
+ LEON_TR_IRQ12 = 0x1C,
+ LEON_TR_IRQ13 = 0x1D,
+ LEON_TR_IRQ14 = 0x1E,
+ LEON_TR_IRQ15 = 0x1F,
+ LEON_TR_SW_MIN = 0x80,
+ LEON_TR_SW_MAX = 0xFF,
+};
--- /dev/null
+/*
+ * (c) 2009 Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#ifndef __ARCH_SPARC_MACROS_H__
+#define __ARCH_SPARC_MACROS_H__
+
+#define L4_CHAR_PTR (char*)
+#define L4_CONST_CHAR_PTR (const char*)
+#define L4_VOID_PTR (void*)
+#define L4_MB_MOD_PTR (l4util_mb_mod_t*)
+
+#endif /* ! __ARCH_SPARC_MACROS_H__ */
--- /dev/null
+/*
+ * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU Lesser General Public License 2.1.
+ * Please see the COPYING-LGPL-2.1 file for details.
+ */
+
+void
+reboot_arch(void) __attribute__((noreturn));
+
+void
+reboot_arch(void)
+{
+ for (;;)
+ ;
+}
--- /dev/null
+/*
+ * bootsect.S Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * modified by Drew Eckhardt
+ * modified by Bruce Evans (bde)
+ * modified by Chris Noe (May 1999) (as86 -> gas)
+ * gutted by H. Peter Anvin (Jan 2003)
+ *
+ * BIG FAT NOTE: We're in real mode using 64k segments. Therefore segment
+ * addresses must be multiplied by 16 to obtain their respective linear
+ * addresses. To avoid confusion, linear addresses are written using leading
+ * hex while segment addresses are written as segment:offset.
+ *
+ */
+
+/* Don't touch these, unless you really know what you're doing. */
+#define DEF_INITSEG 0x9000
+#define DEF_SYSSEG 0x1000
+#define DEF_SETUPSEG 0x9020
+#define DEF_SYSSIZE 0x7F00
+
+/* Internal svga startup constants */
+#define NORMAL_VGA 0xffff /* 80x25 mode */
+#define EXTENDED_VGA 0xfffe /* 80x50 mode */
+#define ASK_VGA 0xfffd /* ask for it at bootup */
+
+
+SETUPSECTS = 6 /* default nr of setup-sectors */
+BOOTSEG = 0x07C0 /* original address of boot-sector */
+INITSEG = DEF_INITSEG /* we move boot here - out of the way */
+SETUPSEG = DEF_SETUPSEG /* setup starts here */
+SYSSEG = DEF_SYSSEG /* system loaded at 0x10000 (65536) */
+SYSSIZE = DEF_SYSSIZE /* system size: # of 16-byte clicks */
+ /* to be loaded */
+ROOT_DEV = 0 /* ROOT_DEV is now written by "build" */
+SWAP_DEV = 0 /* SWAP_DEV is now written by "build" */
+
+#ifndef SVGA_MODE
+#define SVGA_MODE ASK_VGA
+#endif
+
+#ifndef RAMDISK
+#define RAMDISK 0
+#endif
+
+#ifndef ROOT_RDONLY
+#define ROOT_RDONLY 1
+#endif
+
+.code16
+.text
+
+.global _start
+_start:
+
+ # Normalize the start address
+ jmpl $BOOTSEG, $start2
+
+start2:
+ movw %cs, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %ss
+ movw $0x7c00, %sp
+ sti
+ cld
+
+ movw $bugger_off_msg, %si
+
+msg_loop:
+ lodsb
+ andb %al, %al
+ jz die
+ movb $0xe, %ah
+ movw $7, %bx
+ int $0x10
+ jmp msg_loop
+
+die:
+ # Allow the user to press a key, then reboot
+ xorw %ax, %ax
+ int $0x16
+ int $0x19
+
+ # int 0x19 should never return. In case it does anyway,
+ # invoke the BIOS reset code...
+ ljmp $0xf000,$0xfff0
+
+
+bugger_off_msg:
+ .ascii "Direct booting from floppy is no longer supported.\r\n"
+ .ascii "Please use a boot loader program instead.\r\n"
+ .ascii "\n"
+ .ascii "Remove disk and press any key to reboot . . .\r\n"
+ .byte 0
+
+
+ # Kernel attributes; used by setup
+
+ .org 497
+setup_sects: .byte SETUPSECTS
+root_flags: .word ROOT_RDONLY
+syssize: .word SYSSIZE
+swap_dev: .word SWAP_DEV
+ram_size: .word RAMDISK
+vid_mode: .word SVGA_MODE
+root_dev: .word ROOT_DEV
+boot_flag: .word 0xAA55
--- /dev/null
+
+#include "ldscript.inc"
+
+ENTRY(_start)
+
+PHDRS {
+ data PT_LOAD;
+#ifdef IMAGE_MODE
+ mods PT_LOAD;
+#endif
+}
+
+SECTIONS
+{
+#define JH
+#define ENTRY_OFFSET (0x0)
+#ifdef JH
+ #define ENTRY_OFFSET (0xf0000)
+ . = 0;
+
+ /* 16-bit sections */
+ .jh-startup : { *(.jh.startup) }
+
+ . = 0xfff0;
+ .jh-boot : {
+ *(.jh.boot)
+ . = ALIGN(16);
+ }
+#endif
+
+#ifdef ARCH_amd64
+ . = LINKADDR + SIZEOF_HEADERS + ENTRY_OFFSET;
+#else
+ . = LINKADDR;
+#endif
+ PROVIDE (ImageBase = LINKADDR);
+ .hash : AT (ADDR(.hash) - ENTRY_OFFSET) { *(.hash) } : data /* this MUST come first! */
+ /* Merge .text, .rodata, and .data in one segment to save space */
+
+ /* provide at least 1K space for PE header in case of EFI */
+ /* NOTE: the .hash section is not used for EFI, so we declare
+ * this as free space for PE too
+ */
+ /* FXIME: should make this depending on EFI */
+ . = (. < (0x400 + LINKADDR)) ? (LINKADDR + 0x400) : .;
+
+ .text : AT (ADDR(.text) - ENTRY_OFFSET)
+ {
+ *(.init)
+ *(.text .text.* .gnu.linkonce.t*)
+
+ *(.rodata*)
+ } : data
+
+ .dynsym : AT (ADDR(.dynsym) - ENTRY_OFFSET) { *(.dynsym) } : data
+ .dynstr : AT (ADDR(.dynstr) - ENTRY_OFFSET) { *(.dynstr) } : data
+ .reloc : AT (ADDR(.reloc) - ENTRY_OFFSET) { *(.reloc) } : data
+ .rel.dyn : AT (ADDR(.rel.dyn) - ENTRY_OFFSET)
+ {
+ *(.rel.*) *(.rel.module_info)
+ } : data
+
+ .data : AT (ADDR(.data) - ENTRY_OFFSET)
+ {
+ . = ALIGN(8);
+ *(.data)
+ *(.data.*)
+ *(.plt)
+ *(.got.plt)
+ *(.got)
+
+ CTORS
+ PLATFORMS
+
+ } : data
+
+ .data.module_info : AT (ADDR(.data.module_info) - ENTRY_OFFSET)
+ {
+ . = ALIGN(16);
+ _module_info_start = .;
+ *(.module_info .module_info.*)
+ _module_info_end = .;
+ } : data
+
+ .dynamic : AT (ADDR(.dynamic) - ENTRY_OFFSET) { *(.dynamic) } : data
+ .rela.dyn : AT (ADDR(.rela.dyn) - ENTRY_OFFSET)
+ {
+ *(.rela.init)
+ *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+ *(.rela.fini)
+ *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+ *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+ *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+ *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+ *(.rela.ctors)
+ *(.rela.dtors)
+ *(.rela.got)
+ *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+ *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
+ *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
+ *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
+ *(.rela.ifunc)
+ *(.rela.module*)
+ *(.rela.init_array)
+ } : data
+ .rela.plt : AT (ADDR(.rela.plt) - ENTRY_OFFSET)
+ {
+ *(.rela.plt)
+ *(.rela.iplt)
+ } : data
+
+ _edata = .;
+ PROVIDE (edata = .);
+ . = ALIGN(4096);
+ __bss_start = .;
+ .bss : AT (ADDR(.bss) - ENTRY_OFFSET)
+ {
+ *(.bss)
+ *(.bss.*)
+ *(COMMON)
+ *(.dynbss)
+ *(.bss_memmap)
+ } : data
+ _end = . ;
+ PROVIDE (end = .);
+ . = ALIGN(4096);
+
+/* Only move modules to modaddr if bootstrap is being loaded by an elf
+ * loader, and we do not need to copy images around at runtime (e.g. with
+ * compression) */
+#ifdef IMAGE_MODE
+#if defined(PLACE_MODULES_AT_MODADDR) && !defined(SINGLE_SECTION)
+ . = RAM_BASE + MODADDR;
+#endif
+ _module_data_start = .;
+ .module_data : AT (ADDR(.module_data) - ENTRY_OFFSET) {
+ *(EXCLUDE_FILE (*mod00.bin *mod01.bin *mod02.bin) .module_data)
+ *(.module_data)
+ } : mods
+ _module_data_end = .;
+#endif
+
+ /DISCARD/ : {
+ *(.rela.reloc)
+ *(.note.GNU-stack)
+ *(.jcr)
+ *(.interp)
+ *(.comment)
+ *(.note)
+ *(.eh_frame)
+ *(.stab)
+ *(.stabstr)
+ *(.fini)
+ }
+}
--- /dev/null
+/*
+ * (c) 2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ * Frank Mehnert <fm3@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#include <l4/sys/compiler.h>
+#define JH
+#ifdef JH
+#include "inmate.h"
+#define X86_CR0_PE 0x00000001
+
+.code16
+ .section ".jh.boot", "ax"
+
+ .globl __reset_entry
+__reset_entry:
+ ljmp $0xf000,$start16
+
+ .section ".jh.startup", "ax"
+
+start16:
+ lgdtl %cs:gdt_ptr
+
+ mov %cr0,%eax
+ or $X86_CR0_PE,%al
+ mov %eax,%cr0
+
+ ljmpl $INMATE_CS32,$_start + FSEGMENT_BASE
+
+.code32
+
+loader_gdt:
+ .quad 0
+ .quad 0x00cf9b000000ffff
+ .quad 0x00af9b000000ffff
+ .quad 0x00cf93000000ffff
+
+gdt_ptr:
+ .short gdt_ptr - loader_gdt - 1
+ .long loader_gdt + FSEGMENT_BASE
+
+ .align(4096)
+ .global loader_pdpt
+loader_pdpt:
+ .long 0x00000083
+ .align(4096)
+#endif
+
+
+ .section .init
+
+ .globl _start
+_start:
+#ifdef REALMODE_LOADING
+ cld
+ cli
+ mov $(3 * 8), %eax
+ mov %eax, %ds
+ mov %eax, %es
+ mov %eax, %fs
+ mov %eax, %gs
+ mov %eax, %ss
+ lss _stack_seg, %esp
+#else
+ leal _stack, %esp
+#endif
+ pushl $0
+ pushl %esi /* Pointer to real mode or Xen start_info pointer */
+ pushl %eax
+ pushl %ebx
+
+#ifndef XEN
+ /* initialize vector for exception 6 */
+ movl $trap6_entry,%eax
+ movw %ax, _idt_offset_low
+ shrl $16, %eax
+ movw %ax, _idt_offset_high
+ movw %cs, %ax
+ movw %ax, _idt_selector
+
+ /* load tiny interrupt descriptor table to catch exception 6 */
+ lidtl _idtdesc
+#endif
+
+ pushl $_exit
+ jmp __main
+
+ /* Show an error message and wait for keypress to reboot. */
+trap6_entry:
+ pusha
+ cld
+
+ jmp 8f
+
+ /* printhex
+ * edx: value to print
+ * eax: location on screen
+ */
+99: mov %eax, %edi
+ add $(2*8), %edi
+98: mov $numbers,%ebx
+ mov %edx,%ecx
+ shr $28,%ecx
+ shl $4,%edx
+ movzbl (%ebx,%ecx,1),%ecx
+ mov $0x4, %ch
+ mov %cx,(%eax)
+ add $0x2,%eax
+ cmp %edi,%eax
+ jne 98b
+ ret
+
+8:
+ /* print out warning */
+ movl $trap6_warning, %esi
+ movl $(0xb8000 + (24*80*2)), %edi
+ movb $0x0F, %ah
+
+1: /* read next character from string */
+ lodsb
+
+ /* check for end-of-string */
+ cmpb $0, %al
+ je 3f
+
+ /* Check for hex number */
+ cmpb $' ', %al
+ jne 4f
+ pusha
+ mov (32 + 32)(%esp),%edx
+ mov %edi, %eax
+ call 99b
+ popa
+ add $(8*2), %edi
+ jmp 1b
+
+4: /* check for newline */
+ cmpb $'\n', %al
+ jne 2f
+
+ pushl %eax
+ pushl %esi
+
+ /* move screen upwards 1 line */
+ movl $((24*80*2)/4), %ecx
+ movl $(0xb8000 + 1*80*2), %esi
+ movl $0xb8000, %edi
+ rep movsl
+
+ /* clear last line of screen */
+ movl $((1*80*2)/4), %ecx
+ movl $0x07200720, %eax
+ rep stosl
+
+ popl %esi
+ popl %eax
+
+ /* jump to new line */
+ movl $(0xb8000 + (24*80*2)), %edi
+ jmp 1b
+
+2: /* print character */
+ stosw
+ jmp 1b
+
+3: /* wait for keypress */
+ inb $0x64, %al
+ testb $0x01, %al
+ je 3b
+
+ movb %al, %ah
+
+ /* empty keyboard buffer */
+ inb $0x60, %al
+
+ /* ignore PS/2 mouse events */
+ testb $0x20, %ah
+ jne 3b
+
+ jmp reboot
+
+
+ /* the warning text */
+trap6_warning:
+ .ascii "\n"
+ .ascii "Bootstrap: Invalid opcode at detected!\n"
+ .ascii "Be sure that you don't use any CPU optimization flags like\n"
+ .ascii " -march=i686\n"
+ .ascii "when compiling Bootstrap and the depending libraries.\n"
+ .ascii "\n"
+ .asciz " Press any key to reboot..."
+
+numbers:
+ .ascii "0123456789abcdef"
+
+ /* MultiBoot header - see multiboot.h. */
+ .p2align(2)
+
+#define MULTIBOOT_MEMORY_INFO 0x00000002
+_mb_header:
+ .long 0x1BADB002 /* magic */
+ .long MULTIBOOT_MEMORY_INFO /* flags: AOUT_KLUDGE */
+ .long 0 - 0x1BADB002 - MULTIBOOT_MEMORY_INFO
+
+#ifndef XEN
+ .word 0
+_idtdesc:
+ .word (7*8)-1
+ .long _idt
+
+_idt:
+ .word 0,0,0,0 /* trap 0 */
+ .word 0,0,0,0 /* trap 1 */
+ .word 0,0,0,0 /* trap 2 */
+ .word 0,0,0,0 /* trap 3 */
+ .word 0,0,0,0 /* trap 4 */
+ .word 0,0,0,0 /* trap 5 */
+
+_idt_offset_low:
+ .word 0
+_idt_selector:
+ .word 0
+ .byte 0
+ .byte 0xee
+_idt_offset_high:
+ .word 0
+#endif
+
+#ifdef REALMODE_LOADING
+_stack_seg:
+ .long _stack
+ .long (3 * 8)
+#endif
+
+ .bss
+ .space 8192
+ .globl _stack
+_stack:
--- /dev/null
+/*
+ * Jailhouse, a Linux-based partitioning hypervisor
+ *
+ * Copyright (c) Siemens AG, 2013
+ *
+ * Authors:
+ * Jan Kiszka <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#define NULL ((void *)0)
+
+#define HEAP_BASE 0x000000
+#define FSEGMENT_BASE 0x0f0000
+#define COMM_REGION_BASE 0x100000
+
+#define INMATE_CS32 0x8
+#define INMATE_CS64 0x10
+#define INMATE_DS32 0x18
+
+#define NS_PER_USEC 1000UL
+#define NS_PER_MSEC 1000000UL
+#define NS_PER_SEC 1000000000UL
+
+#define PAGE_SIZE (4 * 1024ULL)
+#ifdef __x86_64__
+#define BITS_PER_LONG 64
+#define HUGE_PAGE_SIZE (2 * 1024 * 1024ULL)
+#else
+#define BITS_PER_LONG 32
+#define HUGE_PAGE_SIZE (4 * 1024 * 1024ULL)
+#endif
+#define PAGE_MASK (~(PAGE_SIZE - 1))
+#define HUGE_PAGE_MASK (~(HUGE_PAGE_SIZE - 1))
+
+#define X2APIC_ID 0x802
+#define X2APIC_ICR 0x830
+
+#define APIC_LVL_ASSERT (1 << 14)
+
+#define PCI_CFG_VENDOR_ID 0x000
+#define PCI_CFG_DEVICE_ID 0x002
+#define PCI_CFG_COMMAND 0x004
+# define PCI_CMD_IO (1 << 0)
+# define PCI_CMD_MEM (1 << 1)
+# define PCI_CMD_MASTER (1 << 2)
+# define PCI_CMD_INTX_OFF (1 << 10)
+#define PCI_CFG_STATUS 0x006
+# define PCI_STS_INT (1 << 3)
+# define PCI_STS_CAPS (1 << 4)
+#define PCI_CFG_BAR 0x010
+# define PCI_BAR_64BIT 0x4
+#define PCI_CFG_CAP_PTR 0x034
+
+#define PCI_ID_ANY 0xffff
+
+#define PCI_CAP_MSI 0x05
+#define PCI_CAP_MSIX 0x11
+
+#define MSIX_CTRL_ENABLE 0x8000
+#define MSIX_CTRL_FMASK 0x4000
+
+#define SMP_MAX_CPUS 255
+
+#if 0 //turned off by coon on 11 april. //ifndef __ASSEMBLY__
+typedef signed char s8;
+typedef unsigned char u8;
+
+typedef signed short s16;
+typedef unsigned short u16;
+
+typedef signed int s32;
+typedef unsigned int u32;
+
+typedef signed long long s64;
+typedef unsigned long long u64;
+
+typedef s8 __s8;
+typedef u8 __u8;
+
+typedef s16 __s16;
+typedef u16 __u16;
+
+typedef s32 __s32;
+typedef u32 __u32;
+
+typedef s64 __s64;
+typedef u64 __u64;
+
+typedef enum { true=1, false=0 } bool;
+
+static inline void cpu_relax(void)
+{
+ asm volatile("rep; nop" : : : "memory");
+}
+
+static inline void outb(u8 v, u16 port)
+{
+ asm volatile("outb %0,%1" : : "a" (v), "dN" (port));
+}
+
+static inline void outw(u16 v, u16 port)
+{
+ asm volatile("outw %0,%1" : : "a" (v), "dN" (port));
+}
+
+static inline void outl(u32 v, u16 port)
+{
+ asm volatile("outl %0,%1" : : "a" (v), "dN" (port));
+}
+
+static inline u8 inb(u16 port)
+{
+ u8 v;
+ asm volatile("inb %1,%0" : "=a" (v) : "dN" (port));
+ return v;
+}
+
+static inline u16 inw(u16 port)
+{
+ u16 v;
+ asm volatile("inw %1,%0" : "=a" (v) : "dN" (port));
+ return v;
+}
+
+static inline u32 inl(u16 port)
+{
+ u32 v;
+ asm volatile("inl %1,%0" : "=a" (v) : "dN" (port));
+ return v;
+}
+
+static inline u8 mmio_read8(void *address)
+{
+ return *(volatile u8 *)address;
+}
+
+static inline u16 mmio_read16(void *address)
+{
+ return *(volatile u16 *)address;
+}
+
+static inline u32 mmio_read32(void *address)
+{
+ u32 value;
+
+ /* assembly-encoded to match the hypervisor MMIO parser support */
+ asm volatile("movl (%1),%0" : "=r" (value) : "r" (address));
+ return value;
+}
+
+static inline u64 mmio_read64(void *address)
+{
+ return *(volatile u64 *)address;
+}
+
+static inline void mmio_write8(void *address, u8 value)
+{
+ *(volatile u8 *)address = value;
+}
+
+static inline void mmio_write16(void *address, u16 value)
+{
+ *(volatile u16 *)address = value;
+}
+
+static inline void mmio_write32(void *address, u32 value)
+{
+ /* assembly-encoded to match the hypervisor MMIO parser support */
+ asm volatile("movl %0,(%1)" : : "r" (value), "r" (address));
+}
+
+static inline void mmio_write64(void *address, u64 value)
+{
+ *(volatile u64 *)address = value;
+}
+
+static inline u64 read_msr(unsigned int msr)
+{
+ u32 low, high;
+
+ asm volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (msr));
+ return low | ((u64)high << 32);
+}
+
+static inline void write_msr(unsigned int msr, u64 val)
+{
+ asm volatile("wrmsr"
+ : /* no output */
+ : "c" (msr), "a" ((u32)val), "d" ((u32)(val >> 32))
+ : "memory");
+}
+
+static inline unsigned int cpu_id(void)
+{
+ return read_msr(X2APIC_ID);
+}
+
+#include <jailhouse/hypercall.h>
+
+#define comm_region ((struct jailhouse_comm_region *)COMM_REGION_BASE)
+
+extern unsigned int printk_uart_base;
+void printk(const char *fmt, ...);
+
+void *memset(void *s, int c, unsigned long n);
+void *memcpy(void *d, const void *s, unsigned long n);
+
+typedef void(*int_handler_t)(void);
+
+void int_init(void);
+void int_set_handler(unsigned int vector, int_handler_t handler);
+void int_send_ipi(unsigned int cpu_id, unsigned int vector);
+
+enum ioapic_trigger_mode {
+ TRIGGER_EDGE = 0,
+ TRIGGER_LEVEL_ACTIVE_HIGH = 1 << 15,
+ TRIGGER_LEVEL_ACTIVE_LOW = (1 << 15) | (1 << 13),
+};
+
+void ioapic_init(void);
+void ioapic_pin_set_vector(unsigned int pin,
+ enum ioapic_trigger_mode trigger_mode,
+ unsigned int vector);
+
+void inmate_main(void);
+
+void hypercall_init(void);
+
+unsigned long pm_timer_read(void);
+
+unsigned long tsc_read(void);
+unsigned long tsc_init(void);
+
+void delay_us(unsigned long microsecs);
+
+unsigned long apic_timer_init(unsigned int vector);
+void apic_timer_set(unsigned long timeout_ns);
+
+enum map_type { MAP_CACHED, MAP_UNCACHED };
+
+void *alloc(unsigned long size, unsigned long align);
+void map_range(void *start, unsigned long size, enum map_type map_type);
+
+u32 pci_read_config(u16 bdf, unsigned int addr, unsigned int size);
+void pci_write_config(u16 bdf, unsigned int addr, u32 value,
+ unsigned int size);
+int pci_find_device(u16 vendor, u16 device, u16 start_bdf);
+int pci_find_cap(u16 bdf, u16 cap);
+void pci_msi_set_vector(u16 bdf, unsigned int vector);
+void pci_msix_set_vector(u16 bdf, unsigned int vector, u32 index);
+
+extern volatile u32 smp_num_cpus;
+extern u8 smp_cpu_ids[SMP_MAX_CPUS];
+void smp_wait_for_all_cpus(void);
+void smp_start_cpu(unsigned int cpu_id, void (*entry)(void));
+#endif
--- /dev/null
+/*
+ * (c) 2009 Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#ifndef __ARCH_X86_MACROS_H__
+#define __ARCH_X86_MACROS_H__
+
+#define L4_CHAR_PTR (char*)
+#define L4_CONST_CHAR_PTR (const char*)
+#define L4_VOID_PTR (void*)
+#define L4_MB_MOD_PTR (l4util_mb_mod_t*)
+
+#endif /* ! __ARCH_X86_MACROS_H__ */
--- /dev/null
+/*
+ * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU Lesser General Public License 2.1.
+ * Please see the COPYING-LGPL-2.1 file for details.
+ */
+#include <l4/util/port_io.h>
+#include <l4/util/cpu.h>
+
+void
+reboot_arch(void) __attribute__((noreturn));
+
+void
+reboot_arch(void)
+{
+ while (l4util_in8(0x64) & 0x02)
+ l4util_iodelay();
+ l4util_out8(0x60, 0x64);
+ l4util_iodelay();
+
+ while (l4util_in8(0x64) & 0x02)
+ l4util_iodelay();
+ l4util_out8(0x04, 0x60);
+ l4util_iodelay();
+
+ while (l4util_in8(0x64) & 0x02)
+ l4util_iodelay();
+ l4util_out8(0xFE, 0x64);
+ l4util_iodelay();
+
+ for (;;)
+ l4util_cpu_pause();
+}
--- /dev/null
+/*
+ * setup.S Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * setup.s is responsible for getting the system data from the BIOS,
+ * and putting them into the appropriate places in system memory.
+ * both setup.s and system has been loaded by the bootblock.
+ *
+ * This code asks the bios for memory/disk/other parameters, and
+ * puts them in a "safe" place: 0x90000-0x901FF, ie where the
+ * boot-block used to be. It is then up to the protected mode
+ * system to read them from there before the area is overwritten
+ * for buffer-blocks.
+ *
+ * Move PS/2 aux init code to psaux.c
+ * (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92
+ *
+ * some changes and additional features by Christoph Niemann,
+ * March 1993/June 1994 (Christoph.Niemann@linux.org)
+ *
+ * add APM BIOS checking by Stephen Rothwell, May 1994
+ * (sfr@canb.auug.org.au)
+ *
+ * High load stuff, initrd support and position independency
+ * by Hans Lermen & Werner Almesberger, February 1996
+ * <lermen@elserv.ffm.fgan.de>, <almesber@lrc.epfl.ch>
+ *
+ * Video handling moved to video.S by Martin Mares, March 1996
+ * <mj@k332.feld.cvut.cz>
+ *
+ * Extended memory detection scheme retwiddled by orc@pell.chi.il.us (david
+ * parsons) to avoid loadlin confusion, July 1997
+ *
+ * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999.
+ * <stiker@northlink.com>
+ *
+ * Fix to work around buggy BIOSes which dont use carry bit correctly
+ * and/or report extended memory in CX/DX for e801h memory size detection
+ * call. As a result the kernel got wrong figures. The int15/e801h docs
+ * from Ralf Brown interrupt list seem to indicate AX/BX should be used
+ * anyway. So to avoid breaking many machines (presumably there was a reason
+ * to orginally use CX/DX instead of AX/BX), we do a kludge to see
+ * if CX/DX have been changed in the e801 call and if so use AX/BX .
+ * Michael Miller, April 2001 <michaelm@mjmm.org>
+ *
+ * New A20 code ported from SYSLINUX by H. Peter Anvin. AMD Elan bugfixes
+ * by Robert Schwebel, December 2001 <robert@schwebel.de>
+ */
+
+#define __BIG_KERNEL__ 1
+
+//#include <linux/config.h>
+//#include <asm/segment.h>
+//#include <asm/boot.h>
+
+/* Don't touch these, unless you really know what you're doing. */
+#define DEF_INITSEG 0x9000
+#define DEF_SYSSEG 0x1000
+#define DEF_SETUPSEG 0x9020
+#define DEF_SYSSIZE 0x7F00
+
+/* Internal svga startup constants */
+#define NORMAL_VGA 0xffff /* 80x25 mode */
+#define EXTENDED_VGA 0xfffe /* 80x50 mode */
+#define ASK_VGA 0xfffd /* ask for it at bootup */
+
+
+//#include <asm/e820.h>
+#define E820MAP 0x2d0 /* our map */
+#define E820MAX 32 /* number of entries in E820MAP */
+#define E820NR 0x1e8 /* # entries in E820MAP */
+
+#define E820_RAM 1
+#define E820_RESERVED 2
+#define E820_ACPI 3 /* usable as RAM once ACPI tables have been read
+*/
+#define E820_NVS 4
+
+#define HIGH_MEMORY (1024*1024)
+
+//#include <asm/page.h>
+
+/* Signature words to ensure LILO loaded us right */
+#define SIG1 0xAA55
+#define SIG2 0x5A5A
+
+INITSEG = DEF_INITSEG # 0x9000, we move boot here, out of the way
+SYSSEG = DEF_SYSSEG # 0x1000, system loaded at 0x10000 (65536).
+SETUPSEG = DEF_SETUPSEG # 0x9020, this is the current segment
+ # ... and the former contents of CS
+
+DELTA_INITSEG = SETUPSEG - INITSEG # 0x0020
+
+.code16
+.globl begtext, begdata, begbss, endtext, enddata, endbss
+
+.text
+begtext:
+.data
+begdata:
+.bss
+begbss:
+.text
+
+start:
+ jmp trampoline
+
+# This is the setup header, and it must start at %cs:2 (old 0x9020:2)
+
+ .ascii "HdrS" # header signature
+ .word 0x0203 # header version number (>= 0x0105)
+ # or else old loadlin-1.5 will fail)
+realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
+start_sys_seg: .word SYSSEG
+ .word kernel_version # pointing to kernel version string
+ # above section of header is compatible
+ # with loadlin-1.5 (header v1.5). Don't
+ # change it.
+
+type_of_loader: .byte 0 # = 0, old one (LILO, Loadlin,
+ # Bootlin, SYSLX, bootsect...)
+ # See Documentation/i386/boot.txt for
+ # assigned ids
+
+# flags, unused bits must be zero (RFU) bit within loadflags
+loadflags:
+LOADED_HIGH = 1 # If set, the kernel is loaded high
+CAN_USE_HEAP = 0x80 # If set, the loader also has set
+ # heap_end_ptr to tell how much
+ # space behind setup.S can be used for
+ # heap purposes.
+ # Only the loader knows what is free
+#ifndef __BIG_KERNEL__
+ .byte 0
+#else
+ .byte LOADED_HIGH
+#endif
+
+setup_move_size: .word 0x8000 # size to move, when setup is not
+ # loaded at 0x90000. We will move setup
+ # to 0x90000 then just before jumping
+ # into the kernel. However, only the
+ # loader knows how much data behind
+ # us also needs to be loaded.
+
+code32_start: # here loaders can put a different
+ # start address for 32-bit code.
+#ifndef __BIG_KERNEL__
+ .long 0x1000 # 0x1000 = default for zImage
+#else
+ .long 0x100000 # 0x100000 = default for big kernel
+#endif
+
+ramdisk_image: .long 0 # address of loaded ramdisk image
+ # Here the loader puts the 32-bit
+ # address where it loaded the image.
+ # This only will be read by the kernel.
+
+ramdisk_size: .long 0 # its size in bytes
+
+bootsect_kludge:
+ .long 0 # obsolete
+
+heap_end_ptr: .word modelist+1024 # (Header version 0x0201 or later)
+ # space from here (exclusive) down to
+ # end of setup code can be used by setup
+ # for local heap purposes.
+
+pad1: .word 0
+cmd_line_ptr: .long 0 # (Header version 0x0202 or later)
+ # If nonzero, a 32-bit pointer
+ # to the kernel command line.
+ # The command line should be
+ # located between the start of
+ # setup and the end of low
+ # memory (0xa0000), or it may
+ # get overwritten before it
+ # gets read. If this field is
+ # used, there is no longer
+ # anything magical about the
+ # 0x90000 segment; the setup
+ # can be located anywhere in
+ # low memory 0x10000 or higher.
+
+ramdisk_max: .long (-0xC0000000-(512 << 20)-1) & 0x7fffffff
+ # (Header version 0x0203 or later)
+ # The highest safe address for
+ # the contents of an initrd
+
+trampoline: call start_of_setup
+ .align 16
+ # The offset at this point is 0x240
+ .space (0x7ff-0x240+1) # E820 & EDD space (ending at 0x7ff)
+# End of setup header #####################################################
+
+start_of_setup:
+# Bootlin depends on this being done early
+ movw $0x01500, %ax
+ movb $0x81, %dl
+ int $0x13
+
+#ifdef SAFE_RESET_DISK_CONTROLLER
+# Reset the disk controller.
+ movw $0x0000, %ax
+ movb $0x80, %dl
+ int $0x13
+#endif
+
+# Set %ds = %cs, we know that SETUPSEG = %cs at this point
+ movw %cs, %ax # aka SETUPSEG
+ movw %ax, %ds
+# Check signature at end of setup
+ cmpw $SIG1, setup_sig1
+ jne bad_sig
+
+ cmpw $SIG2, setup_sig2
+ jne bad_sig
+
+ jmp good_sig1
+
+# Routine to print asciiz string at ds:si
+prtstr:
+ lodsb
+ andb %al, %al
+ jz fin
+
+ call prtchr
+ jmp prtstr
+
+fin: ret
+
+# Space printing
+prtsp2: call prtspc # Print double space
+prtspc: movb $0x20, %al # Print single space (note: fall-thru)
+
+# Part of above routine, this one just prints ascii al
+prtchr: pushw %ax
+ pushw %cx
+ movw $7,%bx
+ movw $0x01, %cx
+ movb $0x0e, %ah
+ int $0x10
+ popw %cx
+ popw %ax
+ ret
+
+beep: movb $0x07, %al
+ jmp prtchr
+
+no_sig_mess: .string "No setup signature found ..."
+
+good_sig1:
+ jmp good_sig
+
+# We now have to find the rest of the setup code/data
+bad_sig:
+ movw %cs, %ax # SETUPSEG
+ subw $DELTA_INITSEG, %ax # INITSEG
+ movw %ax, %ds
+ xorb %bh, %bh
+ movb (497), %bl # get setup sect from bootsect
+ subw $4, %bx # LILO loads 4 sectors of setup
+ shlw $8, %bx # convert to words (1sect=2^8 words)
+ movw %bx, %cx
+ shrw $3, %bx # convert to segment
+ addw $SYSSEG, %bx
+ movw %bx, %cs:start_sys_seg
+# Move rest of setup code/data to here
+ movw $2048, %di # four sectors loaded by LILO
+ subw %si, %si
+ pushw %cs
+ popw %es
+ movw $SYSSEG, %ax
+ movw %ax, %ds
+ rep
+ movsw
+ movw %cs, %ax # aka SETUPSEG
+ movw %ax, %ds
+ cmpw $SIG1, setup_sig1
+ jne no_sig
+
+ cmpw $SIG2, setup_sig2
+ jne no_sig
+
+ jmp good_sig
+
+no_sig:
+ lea no_sig_mess, %si
+ call prtstr
+
+no_sig_loop:
+ hlt
+ jmp no_sig_loop
+
+good_sig:
+ movw %cs, %ax # aka SETUPSEG
+ subw $DELTA_INITSEG, %ax # aka INITSEG
+ movw %ax, %ds
+# Check if an old loader tries to load a big-kernel
+ testb $LOADED_HIGH, %cs:loadflags # Do we have a big kernel?
+ jz loader_ok # No, no danger for old loaders.
+
+ cmpb $0, %cs:type_of_loader # Do we have a loader that
+ # can deal with us?
+ jnz loader_ok # Yes, continue.
+
+ pushw %cs # No, we have an old loader,
+ popw %ds # die.
+ lea loader_panic_mess, %si
+ call prtstr
+
+ jmp no_sig_loop
+
+loader_panic_mess: .string "Wrong loader, giving up..."
+
+loader_ok:
+# Get memory size (extended mem, kB)
+
+ xorl %eax, %eax
+ movl %eax, (0x1e0)
+#ifndef STANDARD_MEMORY_BIOS_CALL
+ movb %al, (E820NR)
+# Try three different memory detection schemes. First, try
+# e820h, which lets us assemble a memory map, then try e801h,
+# which returns a 32-bit memory size, and finally 88h, which
+# returns 0-64m
+
+# method E820H:
+# the memory map from hell. e820h returns memory classified into
+# a whole bunch of different types, and allows memory holes and
+# everything. We scan through this memory map and build a list
+# of the first 32 memory areas, which we return at [E820MAP].
+# This is documented at http://www.acpi.info/, in the ACPI 2.0 specification.
+
+#define SMAP 0x534d4150
+
+meme820:
+ xorl %ebx, %ebx # continuation counter
+ movw $E820MAP, %di # point into the whitelist
+ # so we can have the bios
+ # directly write into it.
+
+jmpe820:
+ movl $0x0000e820, %eax # e820, upper word zeroed
+ movl $SMAP, %edx # ascii 'SMAP'
+ movl $20, %ecx # size of the e820rec
+ pushw %ds # data record.
+ popw %es
+ int $0x15 # make the call
+ jc bail820 # fall to e801 if it fails
+
+ cmpl $SMAP, %eax # check the return is `SMAP'
+ jne bail820 # fall to e801 if it fails
+
+# cmpl $1, 16(%di) # is this usable memory?
+# jne again820
+
+ # If this is usable memory, we save it by simply advancing %di by
+ # sizeof(e820rec).
+ #
+good820:
+ movb (E820NR), %al # up to 32 entries
+ cmpb $E820MAX, %al
+ jnl bail820
+
+ incb (E820NR)
+ movw %di, %ax
+ addw $20, %ax
+ movw %ax, %di
+again820:
+ cmpl $0, %ebx # check to see if
+ jne jmpe820 # %ebx is set to EOF
+bail820:
+
+
+# method E801H:
+# memory size is in 1k chunksizes, to avoid confusing loadlin.
+# we store the 0xe801 memory size in a completely different place,
+# because it will most likely be longer than 16 bits.
+# (use 1e0 because that's what Larry Augustine uses in his
+# alternative new memory detection scheme, and it's sensible
+# to write everything into the same place.)
+
+meme801:
+ stc # fix to work around buggy
+ xorw %cx,%cx # BIOSes which dont clear/set
+ xorw %dx,%dx # carry on pass/error of
+ # e801h memory size call
+ # or merely pass cx,dx though
+ # without changing them.
+ movw $0xe801, %ax
+ int $0x15
+ jc mem88
+
+ cmpw $0x0, %cx # Kludge to handle BIOSes
+ jne e801usecxdx # which report their extended
+ cmpw $0x0, %dx # memory in AX/BX rather than
+ jne e801usecxdx # CX/DX. The spec I have read
+ movw %ax, %cx # seems to indicate AX/BX
+ movw %bx, %dx # are more reasonable anyway...
+
+e801usecxdx:
+ andl $0xffff, %edx # clear sign extend
+ shll $6, %edx # and go from 64k to 1k chunks
+ movl %edx, (0x1e0) # store extended memory size
+ andl $0xffff, %ecx # clear sign extend
+ addl %ecx, (0x1e0) # and add lower memory into
+ # total size.
+
+# Ye Olde Traditional Methode. Returns the memory size (up to 16mb or
+# 64mb, depending on the bios) in ax.
+mem88:
+
+#endif
+ movb $0x88, %ah
+ int $0x15
+ movw %ax, (2)
+
+# Set the keyboard repeat rate to the max
+ movw $0x0305, %ax
+ xorw %bx, %bx
+ int $0x16
+
+# Check for video adapter and its parameters and allow the
+# user to browse video modes.
+ call video # NOTE: we need %ds pointing
+ # to bootsector
+
+# Get hd0 data...
+ xorw %ax, %ax
+ movw %ax, %ds
+ ldsw (4 * 0x41), %si
+ movw %cs, %ax # aka SETUPSEG
+ subw $DELTA_INITSEG, %ax # aka INITSEG
+ pushw %ax
+ movw %ax, %es
+ movw $0x0080, %di
+ movw $0x10, %cx
+ pushw %cx
+ cld
+ rep
+ movsb
+# Get hd1 data...
+ xorw %ax, %ax
+ movw %ax, %ds
+ ldsw (4 * 0x46), %si
+ popw %cx
+ popw %es
+ movw $0x0090, %di
+ rep
+ movsb
+# Check that there IS a hd1 :-)
+ movw $0x01500, %ax
+ movb $0x81, %dl
+ int $0x13
+ jc no_disk1
+
+ cmpb $3, %ah
+ je is_disk1
+
+no_disk1:
+ movw %cs, %ax # aka SETUPSEG
+ subw $DELTA_INITSEG, %ax # aka INITSEG
+ movw %ax, %es
+ movw $0x0090, %di
+ movw $0x10, %cx
+ xorw %ax, %ax
+ cld
+ rep
+ stosb
+is_disk1:
+# check for Micro Channel (MCA) bus
+ movw %cs, %ax # aka SETUPSEG
+ subw $DELTA_INITSEG, %ax # aka INITSEG
+ movw %ax, %ds
+ xorw %ax, %ax
+ movw %ax, (0xa0) # set table length to 0
+ movb $0xc0, %ah
+ stc
+ int $0x15 # moves feature table to es:bx
+ jc no_mca
+
+ pushw %ds
+ movw %es, %ax
+ movw %ax, %ds
+ movw %cs, %ax # aka SETUPSEG
+ subw $DELTA_INITSEG, %ax # aka INITSEG
+ movw %ax, %es
+ movw %bx, %si
+ movw $0xa0, %di
+ movw (%si), %cx
+ addw $2, %cx # table length is a short
+ cmpw $0x10, %cx
+ jc sysdesc_ok
+
+ movw $0x10, %cx # we keep only first 16 bytes
+sysdesc_ok:
+ rep
+ movsb
+ popw %ds
+no_mca:
+#ifdef CONFIG_X86_VOYAGER
+ movb $0xff, 0x40 # flag on config found
+ movb $0xc0, %al
+ mov $0xff, %ah
+ int $0x15 # put voyager config info at es:di
+ jc no_voyager
+ movw $0x40, %si # place voyager info in apm table
+ cld
+ movw $7, %cx
+voyager_rep:
+ movb %es:(%di), %al
+ movb %al,(%si)
+ incw %di
+ incw %si
+ decw %cx
+ jnz voyager_rep
+no_voyager:
+#endif
+# Check for PS/2 pointing device
+ movw %cs, %ax # aka SETUPSEG
+ subw $DELTA_INITSEG, %ax # aka INITSEG
+ movw %ax, %ds
+ movw $0, (0x1ff) # default is no pointing device
+ int $0x11 # int 0x11: equipment list
+ testb $0x04, %al # check if mouse installed
+ jz no_psmouse
+
+ movw $0xAA, (0x1ff) # device present
+no_psmouse:
+
+#if defined(CONFIG_X86_SPEEDSTEP_SMI) || defined(CONFIG_X86_SPEEDSTEP_SMI_MODULE)
+ movl $0x0000E980, %eax # IST Support
+ movl $0x47534943, %edx # Request value
+ int $0x15
+
+ movl %eax, (96)
+ movl %ebx, (100)
+ movl %ecx, (104)
+ movl %edx, (108)
+#endif
+
+#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
+# Then check for an APM BIOS...
+ # %ds points to the bootsector
+ movw $0, 0x40 # version = 0 means no APM BIOS
+ movw $0x05300, %ax # APM BIOS installation check
+ xorw %bx, %bx
+ int $0x15
+ jc done_apm_bios # Nope, no APM BIOS
+
+ cmpw $0x0504d, %bx # Check for "PM" signature
+ jne done_apm_bios # No signature, no APM BIOS
+
+ andw $0x02, %cx # Is 32 bit supported?
+ je done_apm_bios # No 32-bit, no (good) APM BIOS
+
+ movw $0x05304, %ax # Disconnect first just in case
+ xorw %bx, %bx
+ int $0x15 # ignore return code
+ movw $0x05303, %ax # 32 bit connect
+ xorl %ebx, %ebx
+ xorw %cx, %cx # paranoia :-)
+ xorw %dx, %dx # ...
+ xorl %esi, %esi # ...
+ xorw %di, %di # ...
+ int $0x15
+ jc no_32_apm_bios # Ack, error.
+
+ movw %ax, (66) # BIOS code segment
+ movl %ebx, (68) # BIOS entry point offset
+ movw %cx, (72) # BIOS 16 bit code segment
+ movw %dx, (74) # BIOS data segment
+ movl %esi, (78) # BIOS code segment lengths
+ movw %di, (82) # BIOS data segment length
+# Redo the installation check as the 32 bit connect
+# modifies the flags returned on some BIOSs
+ movw $0x05300, %ax # APM BIOS installation check
+ xorw %bx, %bx
+ xorw %cx, %cx # paranoia
+ int $0x15
+ jc apm_disconnect # error -> shouldn't happen
+
+ cmpw $0x0504d, %bx # check for "PM" signature
+ jne apm_disconnect # no sig -> shouldn't happen
+
+ movw %ax, (64) # record the APM BIOS version
+ movw %cx, (76) # and flags
+ jmp done_apm_bios
+
+apm_disconnect: # Tidy up
+ movw $0x05304, %ax # Disconnect
+ xorw %bx, %bx
+ int $0x15 # ignore return code
+
+ jmp done_apm_bios
+
+no_32_apm_bios:
+ andw $0xfffd, (76) # remove 32 bit support bit
+done_apm_bios:
+#endif
+
+//#include "edd.S"
+
+# Now we want to move to protected mode ...
+ cmpw $0, %cs:realmode_swtch
+ jz rmodeswtch_normal
+
+ lcall *%cs:realmode_swtch
+
+ jmp rmodeswtch_end
+
+rmodeswtch_normal:
+ pushw %cs
+ call default_switch
+
+rmodeswtch_end:
+# we get the code32 start address and modify the below 'jmpi'
+# (loader may have changed it)
+ movl %cs:code32_start, %eax
+ movl %eax, %cs:code32
+
+# Now we move the system to its rightful place ... but we check if we have a
+# big-kernel. In that case we *must* not move it ...
+ testb $LOADED_HIGH, %cs:loadflags
+ jz do_move0 # .. then we have a normal low
+ # loaded zImage
+ # .. or else we have a high
+ # loaded bzImage
+ jmp end_move # ... and we skip moving
+
+do_move0:
+ movw $0x100, %ax # start of destination segment
+ movw %cs, %bp # aka SETUPSEG
+ subw $DELTA_INITSEG, %bp # aka INITSEG
+ movw %cs:start_sys_seg, %bx # start of source segment
+ cld
+do_move:
+ movw %ax, %es # destination segment
+ incb %ah # instead of add ax,#0x100
+ movw %bx, %ds # source segment
+ addw $0x100, %bx
+ subw %di, %di
+ subw %si, %si
+ movw $0x800, %cx
+ rep
+ movsw
+ cmpw %bp, %bx # assume start_sys_seg > 0x200,
+ # so we will perhaps read one
+ # page more than needed, but
+ # never overwrite INITSEG
+ # because destination is a
+ # minimum one page below source
+ jb do_move
+
+end_move:
+# then we load the segment descriptors
+ movw %cs, %ax # aka SETUPSEG
+ movw %ax, %ds
+
+# Check whether we need to be downward compatible with version <=201
+ cmpl $0, cmd_line_ptr
+ jne end_move_self # loader uses version >=202 features
+ cmpb $0x20, type_of_loader
+ je end_move_self # bootsect loader, we know of it
+
+# Boot loader doesnt support boot protocol version 2.02.
+# If we have our code not at 0x90000, we need to move it there now.
+# We also then need to move the params behind it (commandline)
+# Because we would overwrite the code on the current IP, we move
+# it in two steps, jumping high after the first one.
+ movw %cs, %ax
+ cmpw $SETUPSEG, %ax
+ je end_move_self
+
+ cli # make sure we really have
+ # interrupts disabled !
+ # because after this the stack
+ # should not be used
+ subw $DELTA_INITSEG, %ax # aka INITSEG
+ movw %ss, %dx
+ cmpw %ax, %dx
+ jb move_self_1
+
+ addw $INITSEG, %dx
+ subw %ax, %dx # this will go into %ss after
+ # the move
+move_self_1:
+ movw %ax, %ds
+ movw $INITSEG, %ax # real INITSEG
+ movw %ax, %es
+ movw %cs:setup_move_size, %cx
+ std # we have to move up, so we use
+ # direction down because the
+ # areas may overlap
+ movw %cx, %di
+ decw %di
+ movw %di, %si
+ subw $move_self_here+0x200, %cx
+ rep
+ movsb
+ ljmp $SETUPSEG, $move_self_here
+
+move_self_here:
+ movw $move_self_here+0x200, %cx
+ rep
+ movsb
+ movw $SETUPSEG, %ax
+ movw %ax, %ds
+ movw %dx, %ss
+end_move_self: # now we are at the right place
+
+#
+# Enable A20. This is at the very best an annoying procedure.
+# A20 code ported from SYSLINUX 1.52-1.63 by H. Peter Anvin.
+# AMD Elan bug fix by Robert Schwebel.
+#
+
+#if defined(CONFIG_X86_ELAN)
+ movb $0x02, %al # alternate A20 gate
+ outb %al, $0x92 # this works on SC410/SC520
+a20_elan_wait:
+ call a20_test
+ jz a20_elan_wait
+ jmp a20_done
+#endif
+
+
+A20_TEST_LOOPS = 32 # Iterations per wait
+A20_ENABLE_LOOPS = 255 # Total loops to try
+
+
+#ifndef CONFIG_X86_VOYAGER
+a20_try_loop:
+
+ # First, see if we are on a system with no A20 gate.
+a20_none:
+ call a20_test
+ jnz a20_done
+
+ # Next, try the BIOS (INT 0x15, AX=0x2401)
+a20_bios:
+ movw $0x2401, %ax
+ pushfl # Be paranoid about flags
+ int $0x15
+ popfl
+
+ call a20_test
+ jnz a20_done
+
+ # Try enabling A20 through the keyboard controller
+#endif /* CONFIG_X86_VOYAGER */
+a20_kbc:
+ call empty_8042
+
+#ifndef CONFIG_X86_VOYAGER
+ call a20_test # Just in case the BIOS worked
+ jnz a20_done # but had a delayed reaction.
+#endif
+
+ movb $0xD1, %al # command write
+ outb %al, $0x64
+ call empty_8042
+
+ movb $0xDF, %al # A20 on
+ outb %al, $0x60
+ call empty_8042
+
+#ifndef CONFIG_X86_VOYAGER
+ # Wait until a20 really *is* enabled; it can take a fair amount of
+ # time on certain systems; Toshiba Tecras are known to have this
+ # problem.
+a20_kbc_wait:
+ xorw %cx, %cx
+a20_kbc_wait_loop:
+ call a20_test
+ jnz a20_done
+ loop a20_kbc_wait_loop
+
+ # Final attempt: use "configuration port A"
+a20_fast:
+ inb $0x92, %al # Configuration Port A
+ orb $0x02, %al # "fast A20" version
+ andb $0xFE, %al # don't accidentally reset
+ outb %al, $0x92
+
+ # Wait for configuration port A to take effect
+a20_fast_wait:
+ xorw %cx, %cx
+a20_fast_wait_loop:
+ call a20_test
+ jnz a20_done
+ loop a20_fast_wait_loop
+
+ # A20 is still not responding. Try frobbing it again.
+ #
+ decb (a20_tries)
+ jnz a20_try_loop
+
+ movw $a20_err_msg, %si
+ call prtstr
+
+a20_die:
+ hlt
+ jmp a20_die
+
+a20_tries:
+ .byte A20_ENABLE_LOOPS
+
+a20_err_msg:
+ .ascii "linux: fatal error: A20 gate not responding!"
+ .byte 13, 10, 0
+
+ # If we get here, all is good
+a20_done:
+
+#endif /* CONFIG_X86_VOYAGER */
+# set up gdt and idt
+ lidt idt_48 # load idt with 0,0
+ xorl %eax, %eax # Compute gdt_base
+ movw %ds, %ax # (Convert %ds:gdt to a linear ptr)
+ shll $4, %eax
+ addl $gdt, %eax
+ movl %eax, (gdt_48+2)
+ lgdt gdt_48 # load gdt with whatever is
+ # appropriate
+
+# make sure any possible coprocessor is properly reset..
+ xorw %ax, %ax
+ outb %al, $0xf0
+ call delay
+
+ outb %al, $0xf1
+ call delay
+
+# well, that went ok, I hope. Now we mask all interrupts - the rest
+# is done in init_IRQ().
+ movb $0xFF, %al # mask all interrupts for now
+ outb %al, $0xA1
+ call delay
+
+ movb $0xFB, %al # mask all irq's but irq2 which
+ outb %al, $0x21 # is cascaded
+
+# Well, that certainly wasn't fun :-(. Hopefully it works, and we don't
+# need no steenking BIOS anyway (except for the initial loading :-).
+# The BIOS-routine wants lots of unnecessary data, and it's less
+# "interesting" anyway. This is how REAL programmers do it.
+#
+# Well, now's the time to actually move into protected mode. To make
+# things as simple as possible, we do no register set-up or anything,
+# we let the gnu-compiled 32-bit programs do that. We just jump to
+# absolute address 0x1000 (or the loader supplied one),
+# in 32-bit protected mode.
+#
+# Note that the short jump isn't strictly needed, although there are
+# reasons why it might be a good idea. It won't hurt in any case.
+ movw $1, %ax # protected mode (PE) bit
+ lmsw %ax # This is it!
+ jmp flush_instr
+
+flush_instr:
+ xorw %bx, %bx # Flag to indicate a boot
+ xorl %esi, %esi # Pointer to real-mode code
+ movw %cs, %si
+ subw $DELTA_INITSEG, %si
+ shll $4, %esi # Convert to 32-bit pointer
+
+# jump to startup_32 in arch/i386/boot/compressed/head.S
+#
+# NOTE: For high loaded big kernels we need a
+# jmpi 0x100000,__BOOT_CS
+#
+# but we yet haven't reloaded the CS register, so the default size
+# of the target offset still is 16 bit.
+# However, using an operand prefix (0x66), the CPU will properly
+# take our 48 bit far pointer. (INTeL 80386 Programmer's Reference
+# Manual, Mixing 16-bit and 32-bit code, page 16-6)
+
+ .byte 0x66, 0xea # prefix + jmpi-opcode
+code32: .long 0x1000 # will be set to 0x100000
+ # for big kernels
+ .word 2 * 8
+
+# Here's a bunch of information about your current kernel..
+kernel_version: .ascii "bootstrap"
+ .byte 0
+
+# This is the default real mode switch routine.
+# to be called just before protected mode transition
+default_switch:
+ cli # no interrupts allowed !
+ movb $0x80, %al # disable NMI for bootup
+ # sequence
+ outb %al, $0x70
+ lret
+
+
+#ifndef CONFIG_X86_VOYAGER
+# This routine tests whether or not A20 is enabled. If so, it
+# exits with zf = 0.
+#
+# The memory address used, 0x200, is the int $0x80 vector, which
+# should be safe.
+
+A20_TEST_ADDR = 4*0x80
+
+a20_test:
+ pushw %cx
+ pushw %ax
+ xorw %cx, %cx
+ movw %cx, %fs # Low memory
+ decw %cx
+ movw %cx, %gs # High memory area
+ movw $A20_TEST_LOOPS, %cx
+ movw %fs:(A20_TEST_ADDR), %ax
+ pushw %ax
+a20_test_wait:
+ incw %ax
+ movw %ax, %fs:(A20_TEST_ADDR)
+ call delay # Serialize and make delay constant
+ cmpw %gs:(A20_TEST_ADDR+0x10), %ax
+ loope a20_test_wait
+
+ popw %fs:(A20_TEST_ADDR)
+ popw %ax
+ popw %cx
+ ret
+
+#endif /* CONFIG_X86_VOYAGER */
+
+# This routine checks that the keyboard command queue is empty
+# (after emptying the output buffers)
+#
+# Some machines have delusions that the keyboard buffer is always full
+# with no keyboard attached...
+#
+# If there is no keyboard controller, we will usually get 0xff
+# to all the reads. With each IO taking a microsecond and
+# a timeout of 100,000 iterations, this can take about half a
+# second ("delay" == outb to port 0x80). That should be ok,
+# and should also be plenty of time for a real keyboard controller
+# to empty.
+#
+
+empty_8042:
+ pushl %ecx
+ movl $100000, %ecx
+
+empty_8042_loop:
+ decl %ecx
+ jz empty_8042_end_loop
+
+ call delay
+
+ inb $0x64, %al # 8042 status port
+ testb $1, %al # output buffer?
+ jz no_output
+
+ call delay
+ inb $0x60, %al # read it
+ jmp empty_8042_loop
+
+no_output:
+ testb $2, %al # is input buffer full?
+ jnz empty_8042_loop # yes - loop
+empty_8042_end_loop:
+ popl %ecx
+ ret
+
+# Read the cmos clock. Return the seconds in al
+gettime:
+ pushw %cx
+ movb $0x02, %ah
+ int $0x1a
+ movb %dh, %al # %dh contains the seconds
+ andb $0x0f, %al
+ movb %dh, %ah
+ movb $0x04, %cl
+ shrb %cl, %ah
+ aad
+ popw %cx
+ ret
+
+# Delay is needed after doing I/O
+delay:
+ outb %al,$0x80
+ ret
+
+# Descriptor tables
+#
+# NOTE: The intel manual says gdt should be sixteen bytes aligned for
+# efficiency reasons. However, there are machines which are known not
+# to boot with misaligned GDTs, so alter this at your peril! If you alter
+# GDT_ENTRY_BOOT_CS (in asm/segment.h) remember to leave at least two
+# empty GDT entries (one for NULL and one reserved).
+#
+# NOTE: On some CPUs, the GDT must be 8 byte aligned. This is
+# true for the Voyager Quad CPU card which will not boot without
+# This directive. 16 byte aligment is recommended by intel.
+#
+ .align 16
+gdt:
+ .fill 2,8,0
+
+ .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
+ .word 0 # base address = 0
+ .word 0x9A00 # code read/exec
+ .word 0x00CF # granularity = 4096, 386
+ # (+5th nibble of limit)
+
+ .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
+ .word 0 # base address = 0
+ .word 0x9200 # data read/write
+ .word 0x00CF # granularity = 4096, 386
+ # (+5th nibble of limit)
+gdt_end:
+ .align 4
+
+ .word 0 # alignment byte
+idt_48:
+ .word 0 # idt limit = 0
+ .word 0, 0 # idt base = 0L
+
+ .word 0 # alignment byte
+gdt_48:
+ .word gdt_end - gdt - 1 # gdt limit
+ .word 0, 0 # gdt base (filled in later)
+
+# Include video setup & detection code
+
+/* Enable autodetection of SVGA adapters and modes. */
+#undef CONFIG_VIDEO_SVGA
+
+/* Enable autodetection of VESA modes */
+#define CONFIG_VIDEO_VESA
+
+/* Enable compacting of mode table */
+#define CONFIG_VIDEO_COMPACT
+
+/* Retain screen contents when switching modes */
+#define CONFIG_VIDEO_RETAIN
+
+/* Enable local mode list */
+#undef CONFIG_VIDEO_LOCAL
+
+/* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */
+#undef CONFIG_VIDEO_400_HACK
+
+/* Hack that lets you force specific BIOS mode ID and specific dimensions */
+#undef CONFIG_VIDEO_GFX_HACK
+#define VIDEO_GFX_BIOS_AX 0x4f02 /* 800x600 on ThinkPad */
+#define VIDEO_GFX_BIOS_BX 0x0102
+#define VIDEO_GFX_DUMMY_RESOLUTION 0x6425 /* 100x37 */
+
+/* This code uses an extended set of video mode numbers. These include:
+ * Aliases for standard modes
+ * NORMAL_VGA (-1)
+ * EXTENDED_VGA (-2)
+ * ASK_VGA (-3)
+ * Video modes numbered by menu position -- NOT RECOMMENDED because of lack
+ * of compatibility when extending the table. These are between 0x00 and 0xff.
+ */
+#define VIDEO_FIRST_MENU 0x0000
+
+/* Standard BIOS video modes (BIOS number + 0x0100) */
+#define VIDEO_FIRST_BIOS 0x0100
+
+/* VESA BIOS video modes (VESA number + 0x0200) */
+#define VIDEO_FIRST_VESA 0x0200
+
+/* Video7 special modes (BIOS number + 0x0900) */
+#define VIDEO_FIRST_V7 0x0900
+
+/* Special video modes */
+#define VIDEO_FIRST_SPECIAL 0x0f00
+#define VIDEO_80x25 0x0f00
+#define VIDEO_8POINT 0x0f01
+#define VIDEO_80x43 0x0f02
+#define VIDEO_80x28 0x0f03
+#define VIDEO_CURRENT_MODE 0x0f04
+#define VIDEO_80x30 0x0f05
+#define VIDEO_80x34 0x0f06
+#define VIDEO_80x60 0x0f07
+#define VIDEO_GFX_HACK 0x0f08
+#define VIDEO_LAST_SPECIAL 0x0f09
+
+/* Video modes given by resolution */
+#define VIDEO_FIRST_RESOLUTION 0x1000
+
+/* The "recalculate timings" flag */
+#define VIDEO_RECALC 0x8000
+
+/* Positions of various video parameters passed to the kernel */
+/* (see also include/linux/tty.h) */
+#define PARAM_CURSOR_POS 0x00
+#define PARAM_VIDEO_PAGE 0x04
+#define PARAM_VIDEO_MODE 0x06
+#define PARAM_VIDEO_COLS 0x07
+#define PARAM_VIDEO_EGA_BX 0x0a
+#define PARAM_VIDEO_LINES 0x0e
+#define PARAM_HAVE_VGA 0x0f
+#define PARAM_FONT_POINTS 0x10
+
+#define PARAM_LFB_WIDTH 0x12
+#define PARAM_LFB_HEIGHT 0x14
+#define PARAM_LFB_DEPTH 0x16
+#define PARAM_LFB_BASE 0x18
+#define PARAM_LFB_SIZE 0x1c
+#define PARAM_LFB_LINELENGTH 0x24
+#define PARAM_LFB_COLORS 0x26
+#define PARAM_VESAPM_SEG 0x2e
+#define PARAM_VESAPM_OFF 0x30
+#define PARAM_LFB_PAGES 0x32
+#define PARAM_VESA_ATTRIB 0x34
+
+/* Define DO_STORE according to CONFIG_VIDEO_RETAIN */
+#ifdef CONFIG_VIDEO_RETAIN
+#define DO_STORE call store_screen
+#else
+#define DO_STORE
+#endif /* CONFIG_VIDEO_RETAIN */
+
+# This is the main entry point called by setup.S
+# %ds *must* be pointing to the bootsector
+video: pushw %ds # We use different segments
+ pushw %ds # FS contains original DS
+ popw %fs
+ pushw %cs # DS is equal to CS
+ popw %ds
+ pushw %cs # ES is equal to CS
+ popw %es
+ xorw %ax, %ax
+ movw %ax, %gs # GS is zero
+ cld
+ call basic_detect # Basic adapter type testing (EGA/VGA/MDA/CGA)
+#ifdef CONFIG_VIDEO_SELECT
+ movw %fs:(0x01fa), %ax # User selected video mode
+ cmpw $ASK_VGA, %ax # Bring up the menu
+ jz vid2
+
+ call mode_set # Set the mode
+ jc vid1
+
+ leaw badmdt, %si # Invalid mode ID
+ call prtstr
+vid2: call mode_menu
+vid1:
+#ifdef CONFIG_VIDEO_RETAIN
+ call restore_screen # Restore screen contents
+#endif /* CONFIG_VIDEO_RETAIN */
+ call store_edid
+#endif /* CONFIG_VIDEO_SELECT */
+ call mode_params # Store mode parameters
+ popw %ds # Restore original DS
+ ret
+
+# Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel.
+basic_detect:
+ movb $0, %fs:(PARAM_HAVE_VGA)
+ movb $0x12, %ah # Check EGA/VGA
+ movb $0x10, %bl
+ int $0x10
+ movw %bx, %fs:(PARAM_VIDEO_EGA_BX) # Identifies EGA to the kernel
+ cmpb $0x10, %bl # No, it's a CGA/MDA/HGA card.
+ je basret
+
+ incb adapter
+ movw $0x1a00, %ax # Check EGA or VGA?
+ int $0x10
+ cmpb $0x1a, %al # 1a means VGA...
+ jne basret # anything else is EGA.
+
+ incb %fs:(PARAM_HAVE_VGA) # We've detected a VGA
+ incb adapter
+basret: ret
+
+# Store the video mode parameters for later usage by the kernel.
+# This is done by asking the BIOS except for the rows/columns
+# parameters in the default 80x25 mode -- these are set directly,
+# because some very obscure BIOSes supply insane values.
+mode_params:
+#ifdef CONFIG_VIDEO_SELECT
+ cmpb $0, graphic_mode
+ jnz mopar_gr
+#endif
+ movb $0x03, %ah # Read cursor position
+ xorb %bh, %bh
+ int $0x10
+ movw %dx, %fs:(PARAM_CURSOR_POS)
+ movb $0x0f, %ah # Read page/mode/width
+ int $0x10
+ movw %bx, %fs:(PARAM_VIDEO_PAGE)
+ movw %ax, %fs:(PARAM_VIDEO_MODE) # Video mode and screen width
+ cmpb $0x7, %al # MDA/HGA => segment differs
+ jnz mopar0
+
+ movw $0xb000, video_segment
+mopar0: movw %gs:(0x485), %ax # Font size
+ movw %ax, %fs:(PARAM_FONT_POINTS) # (valid only on EGA/VGA)
+ movw force_size, %ax # Forced size?
+ orw %ax, %ax
+ jz mopar1
+
+ movb %ah, %fs:(PARAM_VIDEO_COLS)
+ movb %al, %fs:(PARAM_VIDEO_LINES)
+ ret
+
+mopar1: movb $25, %al
+ cmpb $0, adapter # If we are on CGA/MDA/HGA, the
+ jz mopar2 # screen must have 25 lines.
+
+ movb %gs:(0x484), %al # On EGA/VGA, use the EGA+ BIOS
+ incb %al # location of max lines.
+mopar2: movb %al, %fs:(PARAM_VIDEO_LINES)
+ ret
+
+#ifdef CONFIG_VIDEO_SELECT
+# Fetching of VESA frame buffer parameters
+mopar_gr:
+ leaw modelist+1024, %di
+ movb $0x23, %fs:(PARAM_HAVE_VGA)
+ movw 16(%di), %ax
+ movw %ax, %fs:(PARAM_LFB_LINELENGTH)
+ movw 18(%di), %ax
+ movw %ax, %fs:(PARAM_LFB_WIDTH)
+ movw 20(%di), %ax
+ movw %ax, %fs:(PARAM_LFB_HEIGHT)
+ movb 25(%di), %al
+ movb $0, %ah
+ movw %ax, %fs:(PARAM_LFB_DEPTH)
+ movb 29(%di), %al
+ movb $0, %ah
+ movw %ax, %fs:(PARAM_LFB_PAGES)
+ movl 40(%di), %eax
+ movl %eax, %fs:(PARAM_LFB_BASE)
+ movl 31(%di), %eax
+ movl %eax, %fs:(PARAM_LFB_COLORS)
+ movl 35(%di), %eax
+ movl %eax, %fs:(PARAM_LFB_COLORS+4)
+ movw 0(%di), %ax
+ movw %ax, %fs:(PARAM_VESA_ATTRIB)
+
+# get video mem size
+ leaw modelist+1024, %di
+ movw $0x4f00, %ax
+ int $0x10
+ xorl %eax, %eax
+ movw 18(%di), %ax
+ movl %eax, %fs:(PARAM_LFB_SIZE)
+
+# switching the DAC to 8-bit is for <= 8 bpp only
+ movw %fs:(PARAM_LFB_DEPTH), %ax
+ cmpw $8, %ax
+ jg dac_done
+
+# get DAC switching capability
+ xorl %eax, %eax
+ movb 10(%di), %al
+ testb $1, %al
+ jz dac_set
+
+# attempt to switch DAC to 8-bit
+ movw $0x4f08, %ax
+ movw $0x0800, %bx
+ int $0x10
+ cmpw $0x004f, %ax
+ jne dac_set
+ movb %bh, dac_size # store actual DAC size
+
+dac_set:
+# set color size to DAC size
+ movb dac_size, %al
+ movb %al, %fs:(PARAM_LFB_COLORS+0)
+ movb %al, %fs:(PARAM_LFB_COLORS+2)
+ movb %al, %fs:(PARAM_LFB_COLORS+4)
+ movb %al, %fs:(PARAM_LFB_COLORS+6)
+
+# set color offsets to 0
+ movb $0, %fs:(PARAM_LFB_COLORS+1)
+ movb $0, %fs:(PARAM_LFB_COLORS+3)
+ movb $0, %fs:(PARAM_LFB_COLORS+5)
+ movb $0, %fs:(PARAM_LFB_COLORS+7)
+
+dac_done:
+# get protected mode interface informations
+ movw $0x4f0a, %ax
+ xorw %bx, %bx
+ xorw %di, %di
+ int $0x10
+ cmp $0x004f, %ax
+ jnz no_pm
+
+ movw %es, %fs:(PARAM_VESAPM_SEG)
+ movw %di, %fs:(PARAM_VESAPM_OFF)
+no_pm: ret
+
+# The video mode menu
+mode_menu:
+ leaw keymsg, %si # "Return/Space/Timeout" message
+ call prtstr
+ call flush
+nokey: call getkt
+
+ cmpb $0x0d, %al # ENTER ?
+ je listm # yes - manual mode selection
+
+ cmpb $0x20, %al # SPACE ?
+ je defmd1 # no - repeat
+
+ call beep
+ jmp nokey
+
+defmd1: ret # No mode chosen? Default 80x25
+
+listm: call mode_table # List mode table
+listm0: leaw name_bann, %si # Print adapter name
+ call prtstr
+ movw card_name, %si
+ orw %si, %si
+ jnz an2
+
+ movb adapter, %al
+ leaw old_name, %si
+ orb %al, %al
+ jz an1
+
+ leaw ega_name, %si
+ decb %al
+ jz an1
+
+ leaw vga_name, %si
+ jmp an1
+
+an2: call prtstr
+ leaw svga_name, %si
+an1: call prtstr
+ leaw listhdr, %si # Table header
+ call prtstr
+ movb $0x30, %dl # DL holds mode number
+ leaw modelist, %si
+lm1: cmpw $ASK_VGA, (%si) # End?
+ jz lm2
+
+ movb %dl, %al # Menu selection number
+ call prtchr
+ call prtsp2
+ lodsw
+ call prthw # Mode ID
+ call prtsp2
+ movb 0x1(%si), %al
+ call prtdec # Rows
+ movb $0x78, %al # the letter 'x'
+ call prtchr
+ lodsw
+ call prtdec # Columns
+ movb $0x0d, %al # New line
+ call prtchr
+ movb $0x0a, %al
+ call prtchr
+ incb %dl # Next character
+ cmpb $0x3a, %dl
+ jnz lm1
+
+ movb $0x61, %dl
+ jmp lm1
+
+lm2: leaw prompt, %si # Mode prompt
+ call prtstr
+ leaw edit_buf, %di # Editor buffer
+lm3: call getkey
+ cmpb $0x0d, %al # Enter?
+ jz lment
+
+ cmpb $0x08, %al # Backspace?
+ jz lmbs
+
+ cmpb $0x20, %al # Printable?
+ jc lm3
+
+ cmpw $edit_buf+4, %di # Enough space?
+ jz lm3
+
+ stosb
+ call prtchr
+ jmp lm3
+
+lmbs: cmpw $edit_buf, %di # Backspace
+ jz lm3
+
+ decw %di
+ movb $0x08, %al
+ call prtchr
+ call prtspc
+ movb $0x08, %al
+ call prtchr
+ jmp lm3
+
+lment: movb $0, (%di)
+ leaw crlft, %si
+ call prtstr
+ leaw edit_buf, %si
+ cmpb $0, (%si) # Empty string = default mode
+ jz lmdef
+
+ cmpb $0, 1(%si) # One character = menu selection
+ jz mnusel
+
+ cmpw $0x6373, (%si) # "scan" => mode scanning
+ jnz lmhx
+
+ cmpw $0x6e61, 2(%si)
+ jz lmscan
+
+lmhx: xorw %bx, %bx # Else => mode ID in hex
+lmhex: lodsb
+ orb %al, %al
+ jz lmuse1
+
+ subb $0x30, %al
+ jc lmbad
+
+ cmpb $10, %al
+ jc lmhx1
+
+ subb $7, %al
+ andb $0xdf, %al
+ cmpb $10, %al
+ jc lmbad
+
+ cmpb $16, %al
+ jnc lmbad
+
+lmhx1: shlw $4, %bx
+ orb %al, %bl
+ jmp lmhex
+
+lmuse1: movw %bx, %ax
+ jmp lmuse
+
+mnusel: lodsb # Menu selection
+ xorb %ah, %ah
+ subb $0x30, %al
+ jc lmbad
+
+ cmpb $10, %al
+ jc lmuse
+
+ cmpb $0x61-0x30, %al
+ jc lmbad
+
+ subb $0x61-0x30-10, %al
+ cmpb $36, %al
+ jnc lmbad
+
+lmuse: call mode_set
+ jc lmdef
+
+lmbad: leaw unknt, %si
+ call prtstr
+ jmp lm2
+lmscan: cmpb $0, adapter # Scanning only on EGA/VGA
+ jz lmbad
+
+ movw $0, mt_end # Scanning of modes is
+ movb $1, scanning # done as new autodetection.
+ call mode_table
+ jmp listm0
+lmdef: ret
+
+# Additional parts of mode_set... (relative jumps, you know)
+setv7: # Video7 extended modes
+ DO_STORE
+ subb $VIDEO_FIRST_V7>>8, %bh
+ movw $0x6f05, %ax
+ int $0x10
+ stc
+ ret
+
+_setrec: jmp setrec # Ugly...
+_set_80x25: jmp set_80x25
+
+# Aliases for backward compatibility.
+setalias:
+ movw $VIDEO_80x25, %ax
+ incw %bx
+ jz mode_set
+
+ movb $VIDEO_8POINT-VIDEO_FIRST_SPECIAL, %al
+ incw %bx
+ jnz setbad # Fall-through!
+
+# Setting of user mode (AX=mode ID) => CF=success
+mode_set:
+ movw %ax, %fs:(0x01fa) # Store mode for use in acpi_wakeup.S
+ movw %ax, %bx
+ cmpb $0xff, %ah
+ jz setalias
+
+ testb $VIDEO_RECALC>>8, %ah
+ jnz _setrec
+
+ cmpb $VIDEO_FIRST_RESOLUTION>>8, %ah
+ jnc setres
+
+ cmpb $VIDEO_FIRST_SPECIAL>>8, %ah
+ jz setspc
+
+ cmpb $VIDEO_FIRST_V7>>8, %ah
+ jz setv7
+
+ cmpb $VIDEO_FIRST_VESA>>8, %ah
+ jnc check_vesa
+
+ orb %ah, %ah
+ jz setmenu
+
+ decb %ah
+ jz setbios
+
+setbad: clc
+ movb $0, do_restore # The screen needn't be restored
+ ret
+
+setvesa:
+ DO_STORE
+ subb $VIDEO_FIRST_VESA>>8, %bh
+ movw $0x4f02, %ax # VESA BIOS mode set call
+ int $0x10
+ cmpw $0x004f, %ax # AL=4f if implemented
+ jnz setbad # AH=0 if OK
+
+ stc
+ ret
+
+setbios:
+ DO_STORE
+ int $0x10 # Standard BIOS mode set call
+ pushw %bx
+ movb $0x0f, %ah # Check if really set
+ int $0x10
+ popw %bx
+ cmpb %bl, %al
+ jnz setbad
+
+ stc
+ ret
+
+setspc: xorb %bh, %bh # Set special mode
+ cmpb $VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL, %bl
+ jnc setbad
+
+ addw %bx, %bx
+ jmp *spec_inits(%bx)
+
+setmenu:
+ orb %al, %al # 80x25 is an exception
+ jz _set_80x25
+
+ pushw %bx # Set mode chosen from menu
+ call mode_table # Build the mode table
+ popw %ax
+ shlw $2, %ax
+ addw %ax, %si
+ cmpw %di, %si
+ jnc setbad
+
+ movw (%si), %ax # Fetch mode ID
+_m_s: jmp mode_set
+
+setres: pushw %bx # Set mode chosen by resolution
+ call mode_table
+ popw %bx
+ xchgb %bl, %bh
+setr1: lodsw
+ cmpw $ASK_VGA, %ax # End of the list?
+ jz setbad
+
+ lodsw
+ cmpw %bx, %ax
+ jnz setr1
+
+ movw -4(%si), %ax # Fetch mode ID
+ jmp _m_s
+
+check_vesa:
+ leaw modelist+1024, %di
+ subb $VIDEO_FIRST_VESA>>8, %bh
+ movw %bx, %cx # Get mode information structure
+ movw $0x4f01, %ax
+ int $0x10
+ addb $VIDEO_FIRST_VESA>>8, %bh
+ cmpw $0x004f, %ax
+ jnz setbad
+
+ movb (%di), %al # Check capabilities.
+ andb $0x19, %al
+ cmpb $0x09, %al
+ jz setvesa # This is a text mode
+
+ movb (%di), %al # Check capabilities.
+ andb $0x99, %al
+ cmpb $0x99, %al
+ jnz _setbad # Doh! No linear frame buffer.
+
+ subb $VIDEO_FIRST_VESA>>8, %bh
+ orw $0x4000, %bx # Use linear frame buffer
+ movw $0x4f02, %ax # VESA BIOS mode set call
+ int $0x10
+ cmpw $0x004f, %ax # AL=4f if implemented
+ jnz _setbad # AH=0 if OK
+
+ movb $1, graphic_mode # flag graphic mode
+ movb $0, do_restore # no screen restore
+ stc
+ ret
+
+_setbad: jmp setbad # Ugly...
+
+# Recalculate vertical display end registers -- this fixes various
+# inconsistencies of extended modes on many adapters. Called when
+# the VIDEO_RECALC flag is set in the mode ID.
+
+setrec: subb $VIDEO_RECALC>>8, %ah # Set the base mode
+ call mode_set
+ jnc rct3
+
+ movw %gs:(0x485), %ax # Font size in pixels
+ movb %gs:(0x484), %bl # Number of rows
+ incb %bl
+ mulb %bl # Number of visible
+ decw %ax # scan lines - 1
+ movw $0x3d4, %dx
+ movw %ax, %bx
+ movb $0x12, %al # Lower 8 bits
+ movb %bl, %ah
+ outw %ax, %dx
+ movb $0x07, %al # Bits 8 and 9 in the overflow register
+ call inidx
+ xchgb %al, %ah
+ andb $0xbd, %ah
+ shrb %bh
+ jnc rct1
+ orb $0x02, %ah
+rct1: shrb %bh
+ jnc rct2
+ orb $0x40, %ah
+rct2: movb $0x07, %al
+ outw %ax, %dx
+ stc
+rct3: ret
+
+# Table of routines for setting of the special modes.
+spec_inits:
+ .word set_80x25
+ .word set_8pixel
+ .word set_80x43
+ .word set_80x28
+ .word set_current
+ .word set_80x30
+ .word set_80x34
+ .word set_80x60
+ .word set_gfx
+
+# Set the 80x25 mode. If already set, do nothing.
+set_80x25:
+ movw $0x5019, force_size # Override possibly broken BIOS
+use_80x25:
+#ifdef CONFIG_VIDEO_400_HACK
+ movw $0x1202, %ax # Force 400 scan lines
+ movb $0x30, %bl
+ int $0x10
+#else
+ movb $0x0f, %ah # Get current mode ID
+ int $0x10
+ cmpw $0x5007, %ax # Mode 7 (80x25 mono) is the only one available
+ jz st80 # on CGA/MDA/HGA and is also available on EGAM
+
+ cmpw $0x5003, %ax # Unknown mode, force 80x25 color
+ jnz force3
+
+st80: cmpb $0, adapter # CGA/MDA/HGA => mode 3/7 is always 80x25
+ jz set80
+
+ movb %gs:(0x0484), %al # This is EGA+ -- beware of 80x50 etc.
+ orb %al, %al # Some buggy BIOS'es set 0 rows
+ jz set80
+
+ cmpb $24, %al # It's hopefully correct
+ jz set80
+#endif /* CONFIG_VIDEO_400_HACK */
+force3: DO_STORE
+ movw $0x0003, %ax # Forced set
+ int $0x10
+set80: stc
+ ret
+
+# Set the 80x50/80x43 8-pixel mode. Simple BIOS calls.
+set_8pixel:
+ DO_STORE
+ call use_80x25 # The base is 80x25
+set_8pt:
+ movw $0x1112, %ax # Use 8x8 font
+ xorb %bl, %bl
+ int $0x10
+ movw $0x1200, %ax # Use alternate print screen
+ movb $0x20, %bl
+ int $0x10
+ movw $0x1201, %ax # Turn off cursor emulation
+ movb $0x34, %bl
+ int $0x10
+ movb $0x01, %ah # Define cursor scan lines 6-7
+ movw $0x0607, %cx
+ int $0x10
+set_current:
+ stc
+ ret
+
+# Set the 80x28 mode. This mode works on all VGA's, because it's a standard
+# 80x25 mode with 14-point fonts instead of 16-point.
+set_80x28:
+ DO_STORE
+ call use_80x25 # The base is 80x25
+set14: movw $0x1111, %ax # Use 9x14 font
+ xorb %bl, %bl
+ int $0x10
+ movb $0x01, %ah # Define cursor scan lines 11-12
+ movw $0x0b0c, %cx
+ int $0x10
+ stc
+ ret
+
+# Set the 80x43 mode. This mode is works on all VGA's.
+# It's a 350-scanline mode with 8-pixel font.
+set_80x43:
+ DO_STORE
+ movw $0x1201, %ax # Set 350 scans
+ movb $0x30, %bl
+ int $0x10
+ movw $0x0003, %ax # Reset video mode
+ int $0x10
+ jmp set_8pt # Use 8-pixel font
+
+# Set the 80x30 mode (all VGA's). 480 scanlines, 16-pixel font.
+set_80x30:
+ call use_80x25 # Start with real 80x25
+ DO_STORE
+ movw $0x3cc, %dx # Get CRTC port
+ inb %dx, %al
+ movb $0xd4, %dl
+ rorb %al # Mono or color?
+ jc set48a
+
+ movb $0xb4, %dl
+set48a: movw $0x0c11, %ax # Vertical sync end (also unlocks CR0-7)
+ call outidx
+ movw $0x0b06, %ax # Vertical total
+ call outidx
+ movw $0x3e07, %ax # (Vertical) overflow
+ call outidx
+ movw $0xea10, %ax # Vertical sync start
+ call outidx
+ movw $0xdf12, %ax # Vertical display end
+ call outidx
+ movw $0xe715, %ax # Vertical blank start
+ call outidx
+ movw $0x0416, %ax # Vertical blank end
+ call outidx
+ pushw %dx
+ movb $0xcc, %dl # Misc output register (read)
+ inb %dx, %al
+ movb $0xc2, %dl # (write)
+ andb $0x0d, %al # Preserve clock select bits and color bit
+ orb $0xe2, %al # Set correct sync polarity
+ outb %al, %dx
+ popw %dx
+ movw $0x501e, force_size
+ stc # That's all.
+ ret
+
+# Set the 80x34 mode (all VGA's). 480 scans, 14-pixel font.
+set_80x34:
+ call set_80x30 # Set 480 scans
+ call set14 # And 14-pt font
+ movw $0xdb12, %ax # VGA vertical display end
+ movw $0x5022, force_size
+setvde: call outidx
+ stc
+ ret
+
+# Set the 80x60 mode (all VGA's). 480 scans, 8-pixel font.
+set_80x60:
+ call set_80x30 # Set 480 scans
+ call set_8pt # And 8-pt font
+ movw $0xdf12, %ax # VGA vertical display end
+ movw $0x503c, force_size
+ jmp setvde
+
+# Special hack for ThinkPad graphics
+set_gfx:
+#ifdef CONFIG_VIDEO_GFX_HACK
+ movw $VIDEO_GFX_BIOS_AX, %ax
+ movw $VIDEO_GFX_BIOS_BX, %bx
+ int $0x10
+ movw $VIDEO_GFX_DUMMY_RESOLUTION, force_size
+ stc
+#endif
+ ret
+
+#ifdef CONFIG_VIDEO_RETAIN
+
+# Store screen contents to temporary buffer.
+store_screen:
+ cmpb $0, do_restore # Already stored?
+ jnz stsr
+
+ testb $CAN_USE_HEAP, loadflags # Have we space for storing?
+ jz stsr
+
+ pushw %ax
+ pushw %bx
+ pushw force_size # Don't force specific size
+ movw $0, force_size
+ call mode_params # Obtain params of current mode
+ popw force_size
+ movb %fs:(PARAM_VIDEO_LINES), %ah
+ movb %fs:(PARAM_VIDEO_COLS), %al
+ movw %ax, %bx # BX=dimensions
+ mulb %ah
+ movw %ax, %cx # CX=number of characters
+ addw %ax, %ax # Calculate image size
+ addw $modelist+1024+4, %ax
+ cmpw heap_end_ptr, %ax
+ jnc sts1 # Unfortunately, out of memory
+
+ movw %fs:(PARAM_CURSOR_POS), %ax # Store mode params
+ leaw modelist+1024, %di
+ stosw
+ movw %bx, %ax
+ stosw
+ pushw %ds # Store the screen
+ movw video_segment, %ds
+ xorw %si, %si
+ rep
+ movsw
+ popw %ds
+ incb do_restore # Screen will be restored later
+sts1: popw %bx
+ popw %ax
+stsr: ret
+
+# Restore screen contents from temporary buffer.
+restore_screen:
+ cmpb $0, do_restore # Has the screen been stored?
+ jz res1
+
+ call mode_params # Get parameters of current mode
+ movb %fs:(PARAM_VIDEO_LINES), %cl
+ movb %fs:(PARAM_VIDEO_COLS), %ch
+ leaw modelist+1024, %si # Screen buffer
+ lodsw # Set cursor position
+ movw %ax, %dx
+ cmpb %cl, %dh
+ jc res2
+
+ movb %cl, %dh
+ decb %dh
+res2: cmpb %ch, %dl
+ jc res3
+
+ movb %ch, %dl
+ decb %dl
+res3: movb $0x02, %ah
+ movb $0x00, %bh
+ int $0x10
+ lodsw # Display size
+ movb %ah, %dl # DL=number of lines
+ movb $0, %ah # BX=phys. length of orig. line
+ movw %ax, %bx
+ cmpb %cl, %dl # Too many?
+ jc res4
+
+ pushw %ax
+ movb %dl, %al
+ subb %cl, %al
+ mulb %bl
+ addw %ax, %si
+ addw %ax, %si
+ popw %ax
+ movb %cl, %dl
+res4: cmpb %ch, %al # Too wide?
+ jc res5
+
+ movb %ch, %al # AX=width of src. line
+res5: movb $0, %cl
+ xchgb %ch, %cl
+ movw %cx, %bp # BP=width of dest. line
+ pushw %es
+ movw video_segment, %es
+ xorw %di, %di # Move the data
+ addw %bx, %bx # Convert BX and BP to _bytes_
+ addw %bp, %bp
+res6: pushw %si
+ pushw %di
+ movw %ax, %cx
+ rep
+ movsw
+ popw %di
+ popw %si
+ addw %bp, %di
+ addw %bx, %si
+ decb %dl
+ jnz res6
+
+ popw %es # Done
+res1: ret
+#endif /* CONFIG_VIDEO_RETAIN */
+
+# Write to indexed VGA register (AL=index, AH=data, DX=index reg. port)
+outidx: outb %al, %dx
+ pushw %ax
+ movb %ah, %al
+ incw %dx
+ outb %al, %dx
+ decw %dx
+ popw %ax
+ ret
+
+# Build the table of video modes (stored after the setup.S code at the
+# `modelist' label. Each video mode record looks like:
+# .word MODE-ID (our special mode ID (see above))
+# .byte rows (number of rows)
+# .byte columns (number of columns)
+# Returns address of the end of the table in DI, the end is marked
+# with a ASK_VGA ID.
+mode_table:
+ movw mt_end, %di # Already filled?
+ orw %di, %di
+ jnz mtab1x
+
+ leaw modelist, %di # Store standard modes:
+ movl $VIDEO_80x25 + 0x50190000, %eax # The 80x25 mode (ALL)
+ stosl
+ movb adapter, %al # CGA/MDA/HGA -- no more modes
+ orb %al, %al
+ jz mtabe
+
+ decb %al
+ jnz mtabv
+
+ movl $VIDEO_8POINT + 0x502b0000, %eax # The 80x43 EGA mode
+ stosl
+ jmp mtabe
+
+mtab1x: jmp mtab1
+
+mtabv: leaw vga_modes, %si # All modes for std VGA
+ movw $vga_modes_end-vga_modes, %cx
+ rep # I'm unable to use movsw as I don't know how to store a half
+ movsb # of the expression above to cx without using explicit shr.
+
+ cmpb $0, scanning # Mode scan requested?
+ jz mscan1
+
+ call mode_scan
+mscan1:
+
+#ifdef CONFIG_VIDEO_LOCAL
+ call local_modes
+#endif /* CONFIG_VIDEO_LOCAL */
+
+#ifdef CONFIG_VIDEO_VESA
+ call vesa_modes # Detect VESA VGA modes
+#endif /* CONFIG_VIDEO_VESA */
+
+#ifdef CONFIG_VIDEO_SVGA
+ cmpb $0, scanning # Bypass when scanning
+ jnz mscan2
+
+ call svga_modes # Detect SVGA cards & modes
+mscan2:
+#endif /* CONFIG_VIDEO_SVGA */
+
+mtabe:
+
+#ifdef CONFIG_VIDEO_COMPACT
+ leaw modelist, %si
+ movw %di, %dx
+ movw %si, %di
+cmt1: cmpw %dx, %si # Scan all modes
+ jz cmt2
+
+ leaw modelist, %bx # Find in previous entries
+ movw 2(%si), %cx
+cmt3: cmpw %bx, %si
+ jz cmt4
+
+ cmpw 2(%bx), %cx # Found => don't copy this entry
+ jz cmt5
+
+ addw $4, %bx
+ jmp cmt3
+
+cmt4: movsl # Copy entry
+ jmp cmt1
+
+cmt5: addw $4, %si # Skip entry
+ jmp cmt1
+
+cmt2:
+#endif /* CONFIG_VIDEO_COMPACT */
+
+ movw $ASK_VGA, (%di) # End marker
+ movw %di, mt_end
+mtab1: leaw modelist, %si # SI=mode list, DI=list end
+ret0: ret
+
+# Modes usable on all standard VGAs
+vga_modes:
+ .word VIDEO_8POINT
+ .word 0x5032 # 80x50
+ .word VIDEO_80x43
+ .word 0x502b # 80x43
+ .word VIDEO_80x28
+ .word 0x501c # 80x28
+ .word VIDEO_80x30
+ .word 0x501e # 80x30
+ .word VIDEO_80x34
+ .word 0x5022 # 80x34
+ .word VIDEO_80x60
+ .word 0x503c # 80x60
+#ifdef CONFIG_VIDEO_GFX_HACK
+ .word VIDEO_GFX_HACK
+ .word VIDEO_GFX_DUMMY_RESOLUTION
+#endif
+
+vga_modes_end:
+# Detect VESA modes.
+
+#ifdef CONFIG_VIDEO_VESA
+vesa_modes:
+ cmpb $2, adapter # VGA only
+ jnz ret0
+
+ movw %di, %bp # BP=original mode table end
+ addw $0x200, %di # Buffer space
+ movw $0x4f00, %ax # VESA Get card info call
+ int $0x10
+ movw %bp, %di
+ cmpw $0x004f, %ax # Successful?
+ jnz ret0
+
+ cmpw $0x4556, 0x200(%di)
+ jnz ret0
+
+ cmpw $0x4153, 0x202(%di)
+ jnz ret0
+
+ movw $vesa_name, card_name # Set name to "VESA VGA"
+ pushw %gs
+ lgsw 0x20e(%di), %si # GS:SI=mode list
+ movw $128, %cx # Iteration limit
+vesa1:
+# gas version 2.9.1, using BFD version 2.9.1.0.23 buggers the next inst.
+# XXX: lodsw %gs:(%si), %ax # Get next mode in the list
+ gs; lodsw
+ cmpw $0xffff, %ax # End of the table?
+ jz vesar
+
+ cmpw $0x0080, %ax # Check validity of mode ID
+ jc vesa2
+
+ orb %ah, %ah # Valid IDs: 0x0000-0x007f/0x0100-0x07ff
+ jz vesan # Certain BIOSes report 0x80-0xff!
+
+ cmpw $0x0800, %ax
+ jnc vesae
+
+vesa2: pushw %cx
+ movw %ax, %cx # Get mode information structure
+ movw $0x4f01, %ax
+ int $0x10
+ movw %cx, %bx # BX=mode number
+ addb $VIDEO_FIRST_VESA>>8, %bh
+ popw %cx
+ cmpw $0x004f, %ax
+ jnz vesan # Don't report errors (buggy BIOSES)
+
+ movb (%di), %al # Check capabilities. We require
+ andb $0x19, %al # a color text mode.
+ cmpb $0x09, %al
+ jnz vesan
+
+ cmpw $0xb800, 8(%di) # Standard video memory address required
+ jnz vesan
+
+ testb $2, (%di) # Mode characteristics supplied?
+ movw %bx, (%di) # Store mode number
+ jz vesa3
+
+ xorw %dx, %dx
+ movw 0x12(%di), %bx # Width
+ orb %bh, %bh
+ jnz vesan
+
+ movb %bl, 0x3(%di)
+ movw 0x14(%di), %ax # Height
+ orb %ah, %ah
+ jnz vesan
+
+ movb %al, 2(%di)
+ mulb %bl
+ cmpw $8193, %ax # Small enough for Linux console driver?
+ jnc vesan
+
+ jmp vesaok
+
+vesa3: subw $0x8108, %bx # This mode has no detailed info specified,
+ jc vesan # so it must be a standard VESA mode.
+
+ cmpw $5, %bx
+ jnc vesan
+
+ movw vesa_text_mode_table(%bx), %ax
+ movw %ax, 2(%di)
+vesaok: addw $4, %di # The mode is valid. Store it.
+vesan: loop vesa1 # Next mode. Limit exceeded => error
+vesae: leaw vesaer, %si
+ call prtstr
+ movw %bp, %di # Discard already found modes.
+vesar: popw %gs
+ ret
+
+# Dimensions of standard VESA text modes
+vesa_text_mode_table:
+ .byte 60, 80 # 0108
+ .byte 25, 132 # 0109
+ .byte 43, 132 # 010A
+ .byte 50, 132 # 010B
+ .byte 60, 132 # 010C
+#endif /* CONFIG_VIDEO_VESA */
+
+# Scan for video modes. A bit dirty, but should work.
+mode_scan:
+ movw $0x0100, %cx # Start with mode 0
+scm1: movb $0, %ah # Test the mode
+ movb %cl, %al
+ int $0x10
+ movb $0x0f, %ah
+ int $0x10
+ cmpb %cl, %al
+ jnz scm2 # Mode not set
+
+ movw $0x3c0, %dx # Test if it's a text mode
+ movb $0x10, %al # Mode bits
+ call inidx
+ andb $0x03, %al
+ jnz scm2
+
+ movb $0xce, %dl # Another set of mode bits
+ movb $0x06, %al
+ call inidx
+ shrb %al
+ jc scm2
+
+ movb $0xd4, %dl # Cursor location
+ movb $0x0f, %al
+ call inidx
+ orb %al, %al
+ jnz scm2
+
+ movw %cx, %ax # Ok, store the mode
+ stosw
+ movb %gs:(0x484), %al # Number of rows
+ incb %al
+ stosb
+ movw %gs:(0x44a), %ax # Number of columns
+ stosb
+scm2: incb %cl
+ jns scm1
+
+ movw $0x0003, %ax # Return back to mode 3
+ int $0x10
+ ret
+
+tstidx: outw %ax, %dx # OUT DX,AX and inidx
+inidx: outb %al, %dx # Read from indexed VGA register
+ incw %dx # AL=index, DX=index reg port -> AL=data
+ inb %dx, %al
+ decw %dx
+ ret
+
+# Try to detect type of SVGA card and supply (usually approximate) video
+# mode table for it.
+
+#ifdef CONFIG_VIDEO_SVGA
+svga_modes:
+ leaw svga_table, %si # Test all known SVGA adapters
+dosvga: lodsw
+ movw %ax, %bp # Default mode table
+ orw %ax, %ax
+ jz didsv1
+
+ lodsw # Pointer to test routine
+ pushw %si
+ pushw %di
+ pushw %es
+ movw $0xc000, %bx
+ movw %bx, %es
+ call *%ax # Call test routine
+ popw %es
+ popw %di
+ popw %si
+ orw %bp, %bp
+ jz dosvga
+
+ movw %bp, %si # Found, copy the modes
+ movb svga_prefix, %ah
+cpsvga: lodsb
+ orb %al, %al
+ jz didsv
+
+ stosw
+ movsw
+ jmp cpsvga
+
+didsv: movw %si, card_name # Store pointer to card name
+didsv1: ret
+
+# Table of all known SVGA cards. For each card, we store a pointer to
+# a table of video modes supported by the card and a pointer to a routine
+# used for testing of presence of the card. The video mode table is always
+# followed by the name of the card or the chipset.
+svga_table:
+ .word ati_md, ati_test
+ .word oak_md, oak_test
+ .word paradise_md, paradise_test
+ .word realtek_md, realtek_test
+ .word s3_md, s3_test
+ .word chips_md, chips_test
+ .word video7_md, video7_test
+ .word cirrus5_md, cirrus5_test
+ .word cirrus6_md, cirrus6_test
+ .word cirrus1_md, cirrus1_test
+ .word ahead_md, ahead_test
+ .word everex_md, everex_test
+ .word genoa_md, genoa_test
+ .word trident_md, trident_test
+ .word tseng_md, tseng_test
+ .word 0
+
+# Test routines and mode tables:
+
+# S3 - The test algorithm was taken from the SuperProbe package
+# for XFree86 1.2.1. Report bugs to Christoph.Niemann@linux.org
+s3_test:
+ movw $0x0f35, %cx # we store some constants in cl/ch
+ movw $0x03d4, %dx
+ movb $0x38, %al
+ call inidx
+ movb %al, %bh # store current CRT-register 0x38
+ movw $0x0038, %ax
+ call outidx # disable writing to special regs
+ movb %cl, %al # check whether we can write special reg 0x35
+ call inidx
+ movb %al, %bl # save the current value of CRT reg 0x35
+ andb $0xf0, %al # clear bits 0-3
+ movb %al, %ah
+ movb %cl, %al # and write it to CRT reg 0x35
+ call outidx
+ call inidx # now read it back
+ andb %ch, %al # clear the upper 4 bits
+ jz s3_2 # the first test failed. But we have a
+
+ movb %bl, %ah # second chance
+ movb %cl, %al
+ call outidx
+ jmp s3_1 # do the other tests
+
+s3_2: movw %cx, %ax # load ah with 0xf and al with 0x35
+ orb %bl, %ah # set the upper 4 bits of ah with the orig value
+ call outidx # write ...
+ call inidx # ... and reread
+ andb %cl, %al # turn off the upper 4 bits
+ pushw %ax
+ movb %bl, %ah # restore old value in register 0x35
+ movb %cl, %al
+ call outidx
+ popw %ax
+ cmpb %ch, %al # setting lower 4 bits was successful => bad
+ je no_s3 # writing is allowed => this is not an S3
+
+s3_1: movw $0x4838, %ax # allow writing to special regs by putting
+ call outidx # magic number into CRT-register 0x38
+ movb %cl, %al # check whether we can write special reg 0x35
+ call inidx
+ movb %al, %bl
+ andb $0xf0, %al
+ movb %al, %ah
+ movb %cl, %al
+ call outidx
+ call inidx
+ andb %ch, %al
+ jnz no_s3 # no, we can't write => no S3
+
+ movw %cx, %ax
+ orb %bl, %ah
+ call outidx
+ call inidx
+ andb %ch, %al
+ pushw %ax
+ movb %bl, %ah # restore old value in register 0x35
+ movb %cl, %al
+ call outidx
+ popw %ax
+ cmpb %ch, %al
+ jne no_s31 # writing not possible => no S3
+ movb $0x30, %al
+ call inidx # now get the S3 id ...
+ leaw idS3, %di
+ movw $0x10, %cx
+ repne
+ scasb
+ je no_s31
+
+ movb %bh, %ah
+ movb $0x38, %al
+ jmp s3rest
+
+no_s3: movb $0x35, %al # restore CRT register 0x35
+ movb %bl, %ah
+ call outidx
+no_s31: xorw %bp, %bp # Detection failed
+s3rest: movb %bh, %ah
+ movb $0x38, %al # restore old value of CRT register 0x38
+ jmp outidx
+
+idS3: .byte 0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95
+ .byte 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0
+
+s3_md: .byte 0x54, 0x2b, 0x84
+ .byte 0x55, 0x19, 0x84
+ .byte 0
+ .ascii "S3"
+ .byte 0
+
+# ATI cards.
+ati_test:
+ leaw idati, %si
+ movw $0x31, %di
+ movw $0x09, %cx
+ repe
+ cmpsb
+ je atiok
+
+ xorw %bp, %bp
+atiok: ret
+
+idati: .ascii "761295520"
+
+ati_md: .byte 0x23, 0x19, 0x84
+ .byte 0x33, 0x2c, 0x84
+ .byte 0x22, 0x1e, 0x64
+ .byte 0x21, 0x19, 0x64
+ .byte 0x58, 0x21, 0x50
+ .byte 0x5b, 0x1e, 0x50
+ .byte 0
+ .ascii "ATI"
+ .byte 0
+
+# AHEAD
+ahead_test:
+ movw $0x200f, %ax
+ movw $0x3ce, %dx
+ outw %ax, %dx
+ incw %dx
+ inb %dx, %al
+ cmpb $0x20, %al
+ je isahed
+
+ cmpb $0x21, %al
+ je isahed
+
+ xorw %bp, %bp
+isahed: ret
+
+ahead_md:
+ .byte 0x22, 0x2c, 0x84
+ .byte 0x23, 0x19, 0x84
+ .byte 0x24, 0x1c, 0x84
+ .byte 0x2f, 0x32, 0xa0
+ .byte 0x32, 0x22, 0x50
+ .byte 0x34, 0x42, 0x50
+ .byte 0
+ .ascii "Ahead"
+ .byte 0
+
+# Chips & Tech.
+chips_test:
+ movw $0x3c3, %dx
+ inb %dx, %al
+ orb $0x10, %al
+ outb %al, %dx
+ movw $0x104, %dx
+ inb %dx, %al
+ movb %al, %bl
+ movw $0x3c3, %dx
+ inb %dx, %al
+ andb $0xef, %al
+ outb %al, %dx
+ cmpb $0xa5, %bl
+ je cantok
+
+ xorw %bp, %bp
+cantok: ret
+
+chips_md:
+ .byte 0x60, 0x19, 0x84
+ .byte 0x61, 0x32, 0x84
+ .byte 0
+ .ascii "Chips & Technologies"
+ .byte 0
+
+# Cirrus Logic 5X0
+cirrus1_test:
+ movw $0x3d4, %dx
+ movb $0x0c, %al
+ outb %al, %dx
+ incw %dx
+ inb %dx, %al
+ movb %al, %bl
+ xorb %al, %al
+ outb %al, %dx
+ decw %dx
+ movb $0x1f, %al
+ outb %al, %dx
+ incw %dx
+ inb %dx, %al
+ movb %al, %bh
+ xorb %ah, %ah
+ shlb $4, %al
+ movw %ax, %cx
+ movb %bh, %al
+ shrb $4, %al
+ addw %ax, %cx
+ shlw $8, %cx
+ addw $6, %cx
+ movw %cx, %ax
+ movw $0x3c4, %dx
+ outw %ax, %dx
+ incw %dx
+ inb %dx, %al
+ andb %al, %al
+ jnz nocirr
+
+ movb %bh, %al
+ outb %al, %dx
+ inb %dx, %al
+ cmpb $0x01, %al
+ je iscirr
+
+nocirr: xorw %bp, %bp
+iscirr: movw $0x3d4, %dx
+ movb %bl, %al
+ xorb %ah, %ah
+ shlw $8, %ax
+ addw $0x0c, %ax
+ outw %ax, %dx
+ ret
+
+cirrus1_md:
+ .byte 0x1f, 0x19, 0x84
+ .byte 0x20, 0x2c, 0x84
+ .byte 0x22, 0x1e, 0x84
+ .byte 0x31, 0x25, 0x64
+ .byte 0
+ .ascii "Cirrus Logic 5X0"
+ .byte 0
+
+# Cirrus Logic 54XX
+cirrus5_test:
+ movw $0x3c4, %dx
+ movb $6, %al
+ call inidx
+ movb %al, %bl # BL=backup
+ movw $6, %ax
+ call tstidx
+ cmpb $0x0f, %al
+ jne c5fail
+
+ movw $0x1206, %ax
+ call tstidx
+ cmpb $0x12, %al
+ jne c5fail
+
+ movb $0x1e, %al
+ call inidx
+ movb %al, %bh
+ movb %bh, %ah
+ andb $0xc0, %ah
+ movb $0x1e, %al
+ call tstidx
+ andb $0x3f, %al
+ jne c5xx
+
+ movb $0x1e, %al
+ movb %bh, %ah
+ orb $0x3f, %ah
+ call tstidx
+ xorb $0x3f, %al
+ andb $0x3f, %al
+c5xx: pushf
+ movb $0x1e, %al
+ movb %bh, %ah
+ outw %ax, %dx
+ popf
+ je c5done
+
+c5fail: xorw %bp, %bp
+c5done: movb $6, %al
+ movb %bl, %ah
+ outw %ax, %dx
+ ret
+
+cirrus5_md:
+ .byte 0x14, 0x19, 0x84
+ .byte 0x54, 0x2b, 0x84
+ .byte 0
+ .ascii "Cirrus Logic 54XX"
+ .byte 0
+
+# Cirrus Logic 64XX -- no known extra modes, but must be identified, because
+# it's misidentified by the Ahead test.
+cirrus6_test:
+ movw $0x3ce, %dx
+ movb $0x0a, %al
+ call inidx
+ movb %al, %bl # BL=backup
+ movw $0xce0a, %ax
+ call tstidx
+ orb %al, %al
+ jne c2fail
+
+ movw $0xec0a, %ax
+ call tstidx
+ cmpb $0x01, %al
+ jne c2fail
+
+ movb $0xaa, %al
+ call inidx # 4X, 5X, 7X and 8X are valid 64XX chip ID's.
+ shrb $4, %al
+ subb $4, %al
+ jz c6done
+
+ decb %al
+ jz c6done
+
+ subb $2, %al
+ jz c6done
+
+ decb %al
+ jz c6done
+
+c2fail: xorw %bp, %bp
+c6done: movb $0x0a, %al
+ movb %bl, %ah
+ outw %ax, %dx
+ ret
+
+cirrus6_md:
+ .byte 0
+ .ascii "Cirrus Logic 64XX"
+ .byte 0
+
+# Everex / Trident
+everex_test:
+ movw $0x7000, %ax
+ xorw %bx, %bx
+ int $0x10
+ cmpb $0x70, %al
+ jne noevrx
+
+ shrw $4, %dx
+ cmpw $0x678, %dx
+ je evtrid
+
+ cmpw $0x236, %dx
+ jne evrxok
+
+evtrid: leaw trident_md, %bp
+evrxok: ret
+
+noevrx: xorw %bp, %bp
+ ret
+
+everex_md:
+ .byte 0x03, 0x22, 0x50
+ .byte 0x04, 0x3c, 0x50
+ .byte 0x07, 0x2b, 0x64
+ .byte 0x08, 0x4b, 0x64
+ .byte 0x0a, 0x19, 0x84
+ .byte 0x0b, 0x2c, 0x84
+ .byte 0x16, 0x1e, 0x50
+ .byte 0x18, 0x1b, 0x64
+ .byte 0x21, 0x40, 0xa0
+ .byte 0x40, 0x1e, 0x84
+ .byte 0
+ .ascii "Everex/Trident"
+ .byte 0
+
+# Genoa.
+genoa_test:
+ leaw idgenoa, %si # Check Genoa 'clues'
+ xorw %ax, %ax
+ movb %es:(0x37), %al
+ movw %ax, %di
+ movw $0x04, %cx
+ decw %si
+ decw %di
+l1: incw %si
+ incw %di
+ movb (%si), %al
+ testb %al, %al
+ jz l2
+
+ cmpb %es:(%di), %al
+l2: loope l1
+ orw %cx, %cx
+ je isgen
+
+ xorw %bp, %bp
+isgen: ret
+
+idgenoa: .byte 0x77, 0x00, 0x99, 0x66
+
+genoa_md:
+ .byte 0x58, 0x20, 0x50
+ .byte 0x5a, 0x2a, 0x64
+ .byte 0x60, 0x19, 0x84
+ .byte 0x61, 0x1d, 0x84
+ .byte 0x62, 0x20, 0x84
+ .byte 0x63, 0x2c, 0x84
+ .byte 0x64, 0x3c, 0x84
+ .byte 0x6b, 0x4f, 0x64
+ .byte 0x72, 0x3c, 0x50
+ .byte 0x74, 0x42, 0x50
+ .byte 0x78, 0x4b, 0x64
+ .byte 0
+ .ascii "Genoa"
+ .byte 0
+
+# OAK
+oak_test:
+ leaw idoakvga, %si
+ movw $0x08, %di
+ movw $0x08, %cx
+ repe
+ cmpsb
+ je isoak
+
+ xorw %bp, %bp
+isoak: ret
+
+idoakvga: .ascii "OAK VGA "
+
+oak_md: .byte 0x4e, 0x3c, 0x50
+ .byte 0x4f, 0x3c, 0x84
+ .byte 0x50, 0x19, 0x84
+ .byte 0x51, 0x2b, 0x84
+ .byte 0
+ .ascii "OAK"
+ .byte 0
+
+# WD Paradise.
+paradise_test:
+ leaw idparadise, %si
+ movw $0x7d, %di
+ movw $0x04, %cx
+ repe
+ cmpsb
+ je ispara
+
+ xorw %bp, %bp
+ispara: ret
+
+idparadise: .ascii "VGA="
+
+paradise_md:
+ .byte 0x41, 0x22, 0x50
+ .byte 0x47, 0x1c, 0x84
+ .byte 0x55, 0x19, 0x84
+ .byte 0x54, 0x2c, 0x84
+ .byte 0
+ .ascii "Paradise"
+ .byte 0
+
+# Trident.
+trident_test:
+ movw $0x3c4, %dx
+ movb $0x0e, %al
+ outb %al, %dx
+ incw %dx
+ inb %dx, %al
+ xchgb %al, %ah
+ xorb %al, %al
+ outb %al, %dx
+ inb %dx, %al
+ xchgb %ah, %al
+ movb %al, %bl # Strange thing ... in the book this wasn't
+ andb $0x02, %bl # necessary but it worked on my card which
+ jz setb2 # is a trident. Without it the screen goes
+ # blurred ...
+ andb $0xfd, %al
+ jmp clrb2
+
+setb2: orb $0x02, %al
+clrb2: outb %al, %dx
+ andb $0x0f, %ah
+ cmpb $0x02, %ah
+ je istrid
+
+ xorw %bp, %bp
+istrid: ret
+
+trident_md:
+ .byte 0x50, 0x1e, 0x50
+ .byte 0x51, 0x2b, 0x50
+ .byte 0x52, 0x3c, 0x50
+ .byte 0x57, 0x19, 0x84
+ .byte 0x58, 0x1e, 0x84
+ .byte 0x59, 0x2b, 0x84
+ .byte 0x5a, 0x3c, 0x84
+ .byte 0
+ .ascii "Trident"
+ .byte 0
+
+# Tseng.
+tseng_test:
+ movw $0x3cd, %dx
+ inb %dx, %al # Could things be this simple ! :-)
+ movb %al, %bl
+ movb $0x55, %al
+ outb %al, %dx
+ inb %dx, %al
+ movb %al, %ah
+ movb %bl, %al
+ outb %al, %dx
+ cmpb $0x55, %ah
+ je istsen
+
+isnot: xorw %bp, %bp
+istsen: ret
+
+tseng_md:
+ .byte 0x26, 0x3c, 0x50
+ .byte 0x2a, 0x28, 0x64
+ .byte 0x23, 0x19, 0x84
+ .byte 0x24, 0x1c, 0x84
+ .byte 0x22, 0x2c, 0x84
+ .byte 0x21, 0x3c, 0x84
+ .byte 0
+ .ascii "Tseng"
+ .byte 0
+
+# Video7.
+video7_test:
+ movw $0x3cc, %dx
+ inb %dx, %al
+ movw $0x3b4, %dx
+ andb $0x01, %al
+ jz even7
+
+ movw $0x3d4, %dx
+even7: movb $0x0c, %al
+ outb %al, %dx
+ incw %dx
+ inb %dx, %al
+ movb %al, %bl
+ movb $0x55, %al
+ outb %al, %dx
+ inb %dx, %al
+ decw %dx
+ movb $0x1f, %al
+ outb %al, %dx
+ incw %dx
+ inb %dx, %al
+ movb %al, %bh
+ decw %dx
+ movb $0x0c, %al
+ outb %al, %dx
+ incw %dx
+ movb %bl, %al
+ outb %al, %dx
+ movb $0x55, %al
+ xorb $0xea, %al
+ cmpb %bh, %al
+ jne isnot
+
+ movb $VIDEO_FIRST_V7>>8, svga_prefix # Use special mode switching
+ ret
+
+video7_md:
+ .byte 0x40, 0x2b, 0x50
+ .byte 0x43, 0x3c, 0x50
+ .byte 0x44, 0x3c, 0x64
+ .byte 0x41, 0x19, 0x84
+ .byte 0x42, 0x2c, 0x84
+ .byte 0x45, 0x1c, 0x84
+ .byte 0
+ .ascii "Video 7"
+ .byte 0
+
+# Realtek VGA
+realtek_test:
+ leaw idrtvga, %si
+ movw $0x45, %di
+ movw $0x0b, %cx
+ repe
+ cmpsb
+ je isrt
+
+ xorw %bp, %bp
+isrt: ret
+
+idrtvga: .ascii "REALTEK VGA"
+
+realtek_md:
+ .byte 0x1a, 0x3c, 0x50
+ .byte 0x1b, 0x19, 0x84
+ .byte 0x1c, 0x1e, 0x84
+ .byte 0x1d, 0x2b, 0x84
+ .byte 0x1e, 0x3c, 0x84
+ .byte 0
+ .ascii "REALTEK"
+ .byte 0
+
+#endif /* CONFIG_VIDEO_SVGA */
+
+# User-defined local mode table (VGA only)
+#ifdef CONFIG_VIDEO_LOCAL
+local_modes:
+ leaw local_mode_table, %si
+locm1: lodsw
+ orw %ax, %ax
+ jz locm2
+
+ stosw
+ movsw
+ jmp locm1
+
+locm2: ret
+
+# This is the table of local video modes which can be supplied manually
+# by the user. Each entry consists of mode ID (word) and dimensions
+# (byte for column count and another byte for row count). These modes
+# are placed before all SVGA and VESA modes and override them if table
+# compacting is enabled. The table must end with a zero word followed
+# by NUL-terminated video adapter name.
+local_mode_table:
+ .word 0x0100 # Example: 40x25
+ .byte 25,40
+ .word 0
+ .ascii "Local"
+ .byte 0
+#endif /* CONFIG_VIDEO_LOCAL */
+
+# Read a key and return the ASCII code in al, scan code in ah
+getkey: xorb %ah, %ah
+ int $0x16
+ ret
+
+# Read a key with a timeout of 30 seconds.
+# The hardware clock is used to get the time.
+getkt: call gettime
+ addb $30, %al # Wait 30 seconds
+ cmpb $60, %al
+ jl lminute
+
+ subb $60, %al
+lminute:
+ movb %al, %cl
+again: movb $0x01, %ah
+ int $0x16
+ jnz getkey # key pressed, so get it
+
+ call gettime
+ cmpb %cl, %al
+ jne again
+
+ movb $0x20, %al # timeout, return `space'
+ ret
+
+# Flush the keyboard buffer
+flush: movb $0x01, %ah
+ int $0x16
+ jz empty
+
+ xorb %ah, %ah
+ int $0x16
+ jmp flush
+
+empty: ret
+
+# Print hexadecimal number.
+prthw: pushw %ax
+ movb %ah, %al
+ call prthb
+ popw %ax
+prthb: pushw %ax
+ shrb $4, %al
+ call prthn
+ popw %ax
+ andb $0x0f, %al
+prthn: cmpb $0x0a, %al
+ jc prth1
+
+ addb $0x07, %al
+prth1: addb $0x30, %al
+ jmp prtchr
+
+# Print decimal number in al
+prtdec: pushw %ax
+ pushw %cx
+ xorb %ah, %ah
+ movb $0x0a, %cl
+ idivb %cl
+ cmpb $0x09, %al
+ jbe lt100
+
+ call prtdec
+ jmp skip10
+
+lt100: addb $0x30, %al
+ call prtchr
+skip10: movb %ah, %al
+ addb $0x30, %al
+ call prtchr
+ popw %cx
+ popw %ax
+ ret
+
+store_edid:
+ pushw %es # just save all registers
+ pushw %ax
+ pushw %bx
+ pushw %cx
+ pushw %dx
+ pushw %di
+
+ pushw %fs
+ popw %es
+
+ movl $0x13131313, %eax # memset block with 0x13
+ movw $32, %cx
+ movw $0x140, %di
+ cld
+ rep
+ stosl
+
+ movw $0x4f15, %ax # do VBE/DDC
+ movw $0x01, %bx
+ movw $0x00, %cx
+ movw $0x01, %dx
+ movw $0x140, %di
+ int $0x10
+
+ popw %di # restore all registers
+ popw %dx
+ popw %cx
+ popw %bx
+ popw %ax
+ popw %es
+ ret
+
+# VIDEO_SELECT-only variables
+mt_end: .word 0 # End of video mode table if built
+edit_buf: .space 6 # Line editor buffer
+card_name: .word 0 # Pointer to adapter name
+scanning: .byte 0 # Performing mode scan
+do_restore: .byte 0 # Screen contents altered during mode change
+svga_prefix: .byte VIDEO_FIRST_BIOS>>8 # Default prefix for BIOS modes
+graphic_mode: .byte 0 # Graphic mode with a linear frame buffer
+dac_size: .byte 6 # DAC bit depth
+
+# Status messages
+keymsg: .ascii "Press <RETURN> to see video modes available, "
+ .ascii "<SPACE> to continue or wait 30 secs"
+ .byte 0x0d, 0x0a, 0
+
+listhdr: .byte 0x0d, 0x0a
+ .ascii "Mode: COLSxROWS:"
+
+crlft: .byte 0x0d, 0x0a, 0
+
+prompt: .byte 0x0d, 0x0a
+ .asciz "Enter mode number or `scan': "
+
+unknt: .asciz "Unknown mode ID. Try again."
+
+badmdt: .ascii "You passed an undefined mode number."
+ .byte 0x0d, 0x0a, 0
+
+vesaer: .ascii "Error: Scanning of VESA modes failed. Please "
+ .ascii "report to <mj@ucw.cz>."
+ .byte 0x0d, 0x0a, 0
+
+old_name: .asciz "CGA/MDA/HGA"
+
+ega_name: .asciz "EGA"
+
+svga_name: .ascii " "
+
+vga_name: .asciz "VGA"
+
+vesa_name: .asciz "VESA"
+
+name_bann: .asciz "Video adapter: "
+#endif /* CONFIG_VIDEO_SELECT */
+
+# Other variables:
+adapter: .byte 0 # Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA
+video_segment: .word 0xb800 # Video memory segment
+force_size: .word 0 # Use this size instead of the one in BIOS vars
+
+# Setup signature -- must be last
+setup_sig1: .word SIG1
+setup_sig2: .word SIG2
+
+# After this point, there is some free space which is used by the video mode
+# handling code to store the temporary mode table (not used by the kernel).
+
+modelist:
+
+.text
+endtext:
+.data
+enddata:
+.bss
+endbss:
+
--- /dev/null
+
+#include <h/types.h>
+#include <h/os.h>
+#include <h/hypervisor.h>
+#include <public/xen.h>
+
+asm(".section __xen_guest \n"
+ ".ascii \"GUEST_OS=DD-L4\" \n"
+ ".ascii \",GUEST_VER=0.1\" \n"
+ ".ascii \",XEN_VER=2.0\" \n"
+ ".ascii \",VIRT_BASE=0xf0000000\" \n"
+ ".ascii \",LOADER=generic\" \n"
+ ".ascii \",PT_MODE_WRITABLE\" \n"
+ ".previous \n");
+
+int
+putchar(int c)
+{
+ HYPERVISOR_console_io(CONSOLEIO_write, 1, (char *)&c);
+ return c;
+}
--- /dev/null
+# vim:set ft=make:
+#
+# User definable variables for bootstrap:
+# - BOOTSTRAP_CHECK_MD5 set this if you want MD5 checks for modules
+# - BOOTSTRAP_SEARCH_PATH
+# - BOOTSTRAP_ELF_NAME
+# - BOOTSTRAP_MODULES_LIST
+# - BOOTSTRAP_DO_RAW_IMAGE
+# - BOOTSTRAP_DO_UIMAGE
+# - BOOTSTRAP_DO_UEFI if set an image which is bootable by UEFI is built
+# - BOOTSTRAP_NO_STRIP if set no stripping of image
+# - BOOTSTRAP_UIMAGE_COMPRESSION: set to none, gzip, or bzip2
+# - BOOTSTRAP_CMDLINE: compiled-in command line, only used if no cmdline
+# given
+# - BOOTSTRAP_OUTPUT_DIR: Optional alternative output directory for all
+# images (and generated files), preferable some
+# tmpfs directory
+
+INTERNAL_CRT0 := y # the defualt is to use our internal crt0
+DEFAULT_RELOC_arm := 0x01000000
+DEFAULT_RELOC_x86 := 0x002d0000
+DEFAULT_RELOC_amd64 := 0x002d0000
+DEFAULT_RELOC_ppc32 := 0x002d0000
+DEFAULT_RELOC_sparc := 0x00800000
+RELOC_PHYS := y
+LDFLAGS = -nostdlib -static -Bstatic
+EXTRA_GENERAL_D_DEP += .redo-change-tracker $(BID_RAM_BASE_DEP) \
+ $(wildcard $(L4DIR)/conf/Makeconf.boot $(OBJ_BASE)/conf/Makeconf.boot) \
+ $(SRC_DIR)/build.pl $(BOOTSTRAP_MODULES_LIST)
+INCLUDE_MAKE_RULES = $(SRC_DIR)/*/Make.rules
+BOOTSTRAP_LD_dep := $(SRC_DIR)/ldscript.inc
+
+ifneq ($(BOOTSTRAP_CHECK_MD5),)
+ REQUIRES_LIBS += libbsd-lite
+ DEFINES += -DDO_CHECK_MD5
+endif
+
+include $(L4DIR)/mk/Makeconf
+-include $(OBJ_DIR)/Makeconf.local
+-include $(L4DIR)/conf/Makeconf.boot
+-include $(OBJ_BASE)/conf/Makeconf.boot
+
+SRC_CC_IS_CXX11 := y
+
+# Checks added Nov 2010:
+ifneq ($(wildcard $(L4DIR)/conf/Makeconf.bootstrap),)
+$(error $(L4DIR)/conf/Makeconf.bootstrap not used anymore. Please use $(L4DIR)/conf/Makeconf.boot now)
+endif
+ifneq ($(wildcard $(OBJ_BASE)/Makeconf.bootstrap),)
+$(error $(OBJ_BASE)/Makeconf.bootstrap not used anymore. Please use $(OBJ_BASE)/conf/Makeconf.boot now)
+endif
+
+ifeq ($(BOOTSTRAP_DO_UEFI),y)
+ # link to 0x0
+ DEFAULT_RELOC_x86 := 0x0
+ DEFAULT_RELOC_amd64 := 0x0
+
+ BUILD_PIE := 1
+
+ # lib gnu-efi requirements
+ REQUIRES_LIBS += gnu-efi
+ EFI_ARCH-amd64 := x86_64
+ EFI_ARCH-x86 := ia32
+ EFI_ARCH := $(EFI_ARCH-$(ARCH))
+ EFI_BIN_FMT := efi-app-$(EFI_ARCH)
+ CRTN_dyn_bin :=
+ CRTEND_dyn_bin :=
+ INTERNAL_CRT0 := n
+ CRT0 = $(OBJ_BASE)/lib/$(SYSTEM)/crt0-efi-$(EFI_ARCH).o
+ EXTRA_LIBS = -L$(OBJ_BASE)/lib/$(SYSTEM) -lefi -lgnuefi
+ CXXFLAGS += -fshort-wchar
+ CFLAGS += -fshort-wchar
+endif
+
+BOOTSTRAP_SEARCH_PATH ?= $(OBJ_DIR)
+BOOTSTRAP_MODULES_LIST ?= $(SRC_DIR)/modules.list
+BOOTSTRAP_MODULE_PATH_BINLIB ?= $(OBJ_BASE)/bin/$(SYSTEM)/$(BUILD_ABI):$(OBJ_BASE)/lib/$(SYSTEM)/$(BUILD_ABI):$(OBJ_BASE)/lib/$(SYSTEM)
+BOOTSTRAP_ELF_NAME ?= bootstrap.elf
+MKIMAGE ?= mkimage
+BOOTSTRAP_UIMAGE_COMPRESSION ?= none
+
+ifeq ($(BUILD_ARCH),$(filter $(BUILD_ARCH),arm ppc32 sparc))
+ # ARM/PPC/SPARC always uses single image mode
+ # when no entry is given we build the useless auto-build target
+ ifeq ($(E)$(ENTRY),)
+ BOOTSTRAP_ELF_NAME := bootstrap.auto-build-useless.elf
+ endif
+ ENTRY := auto-build-entry
+endif
+
+od := $(if $(BOOTSTRAP_OUTPUT_DIR),$(if $(wildcard $(BOOTSTRAP_OUTPUT_DIR)),,$(shell mkdir $(BOOTSTRAP_OUTPUT_DIR))))
+od := $(if $(BOOTSTRAP_OUTPUT_DIR),$(BOOTSTRAP_OUTPUT_DIR)/)
+
+PRIVATE_INCDIR = $(SRC_DIR) $(SRC_DIR)/ARCH-$(ARCH)
+
+TARGET := $(od)$(BOOTSTRAP_ELF_NAME)
+TARGET_BIN = $(od)$(BOOTSTRAP_ELF_NAME)
+MODE = lib
+
+include $(SRC_DIR)/Makefile.platform
+
+ifneq ($(DEFAULT_RELOC_arm-$(PLATFORM_TYPE)),)
+DEFAULT_RELOC_arm := $(DEFAULT_RELOC_arm-$(PLATFORM_TYPE))
+endif
+
+INTERNAL_CRT0 := $(strip $(INTERNAL_CRT0))
+
+CXXFLAGS_amd64 += -mno-sse
+CXXFLAGS_x86 += -mno-sse
+CFLAGS_amd64 += -mno-sse
+CFLAGS_x86 += -mno-sse
+
+SRC_C += exec.c module.c
+SRC_CC += region.cc startup.cc init_kip_f.cc \
+ libc_support+.cc patch.cc koptions.cc \
+ platform_common.cc memory.cc boot_modules.cc
+
+SRC_CC_x86 += ARCH-x86/reboot.cc
+SRC_CC_amd64 += ARCH-x86/reboot.cc
+SRC_C_x86 += base_critical.c
+SRC_C_amd64 += base_critical.c
+SRC_CC_arm += ARCH-arm/reboot.cc ARCH-arm/head.cc
+SRC_CC_ppc32 += ARCH-ppc32/init_kip_v2-arch.cc \
+ ARCH-ppc32/reboot.cc ARCH-ppc32/head.cc
+SRC_CC_sparc += ARCH-sparc/reboot.cc ARCH-sparc/head.cc
+SRC_CC += $(SUPPORT_CC_$(ARCH)-$(PLATFORM_TYPE))
+
+SRC_S-$(INTERNAL_CRT0) += ARCH-$(ARCH)/crt0.S
+
+OPTS = -g -Os $(CARCHFLAGS_$(ARCH)) $(CARCHFLAGS_$(ARCH)_$(CPU)) \
+ $(GCCNOFPU_$(ARCH))
+DEFINES += -DRAM_BASE=$(RAM_BASE) -DL4_MINIMAL_LIBC=1
+DEFINES += -DCMDLINE="\"$(BOOTSTRAP_CMDLINE)\""
+DEFINES += -DPLATFORM_TYPE=\"$(PLATFORM_TYPE)\"
+DEFINES += -DPLATFORM_TYPE_$(PLATFORM_TYPE)
+DEFINES += -DPLATFORM_UART_NR=$(PLATFORM_UART_NR)
+
+MOD_ADDR = 0x02000000
+
+SRC_S += $(SRC_S-y)
+CPPFLAGS += $(CPPFLAGS_$(ARCH)-$(PLATFORM_TYPE))
+CPPFLAGS += $(BID_PKG_CONFIG_CFLAGS)
+
+ifeq ($(filter clean cleanall,$(MAKECMDGOALS)),)
+ifeq ($(SUPPORT_CC_$(ARCH)-$(PLATFORM_TYPE)),)
+ $(info ERROR: PLATFORM_TYPE=$(PLATFORM_TYPE) has no assigned platform support file)
+ $(info ERROR: A proper PLATFORM_TYPE must be set for a build)
+ $(error .)
+endif
+endif
+
+BOOTSTRAP_L4_LIBS := -lcxx_base -lcxx_io -luc_c_minimal
+DRV_LIBS-ppc32 = -ldrivers_of
+DRV_LIBS = -ldrivers_uart $(DRV_LIBS-$(ARCH))
+ifeq ($(INTERNAL_CRT0),y)
+CRT0 =
+endif
+LDSCRIPT = bootstrap.ld
+LDNMAGIC =
+
+vpath bootstrap.ld.in $(SRC_DIR)/ARCH-$(ARCH)
+
+# can be overwritten by Makeconf.local
+COMPRESS ?= 0
+REALMODE_LOADING ?= 0
+RML ?= 0
+BUILD_PIE ?= 0
+SPARSE_ELF ?= n
+
+ifeq ($(BUILD_PIE),1)
+DRV_LIBS := $(patsubst -l%,-l%.p,$(DRV_LIBS))
+BOOTSTRAP_L4_LIBS := $(patsubst -l%,-l%.p,$(BOOTSTRAP_L4_LIBS))
+CFLAGS += -fpie
+CXXFLAGS += -fpie
+DEFINES += -D__PIC__
+LDFLAGS = -znocombreloc -nostdlib -pie -Bsymbolic
+endif
+
+ifneq ($(REALMODE_LOADING)$(RML),00)
+REALMODE_LOADING := 1
+#$(error Info: Default reloc needs to be 0x00100000)
+# And if you have done so you probably need to relink sigma0 and/or moe
+endif
+
+ifeq ($(ARCH),arm)
+CPPFLAGS += -DSINGLE_SECTION
+endif
+
+
+
+# convenience
+ifneq ($(E),)
+ENTRY := $(E)
+endif
+
+ENTRY_FN := $(shell echo "$(ENTRY)" | tr '[ ]' '[_]' )
+
+
+ifneq ($(ENTRY),)
+ ifeq ($(filter clean cleanall,$(MAKECMDGOALS)),)
+ BUILD_MOD_CMD = ( SEARCHPATH="$(BOOTSTRAP_SEARCH_PATH):$(BOOTSTRAP_MODULE_PATH_BINLIB)" \
+ CC="$(CC)" LD="$(LD)" CROSS_COMPILE=$(CROSS_COMPILE) \
+ MAKE_INC_FILE=$(PWD)/mod.make.inc \
+ FLAGS_CC="$(CCXX_FLAGS) -I$(SRC_DIR)" \
+ OUTPUT_DIR="$(BOOTSTRAP_OUTPUT_DIR)" \
+ OPT_ARCH=$(ARCH) OPT_COMPRESS=$(COMPRESS) L4DIR=$(L4DIR) \
+ $(SRC_DIR)/build.pl $(1) $(BOOTSTRAP_MODULES_LIST) "$(ENTRY)" || \
+ (echo "processing-of-module-list-failed"; exit 1))
+ endif
+endif
+
+
+# we need to re-do if some things change
+.redo-change-tracker: FORCE
+ $(VERBOSE)echo "$(ENTRY) '$(COMPRESS)' '$(BOOTSTRAP_CMDLINE)' '$(BOOTSTRAP_SEARCH_PATH):$(BOOTSTRAP_MODULE_PATH_BINLIB)' '$(RAM_SIZE_MB)' '$(PLATFORM_TYPE)' '$(PLATFORM_UART_NR)' '$(od)' '$(OPT_STRIP)'" > $@.tmp
+ $(if $(BUILD_MOD_CMD),$(VERBOSE)$(call BUILD_MOD_CMD,dump) >> $@.tmp)
+ $(call move_if_changed,$@,$@.tmp)
+
+ifneq ($(ENTRY),)
+
+INSTALL_FILES = $(BOOTSTRAP_ELF_NAME) bootstrap_$(ENTRY_FN) bootstrap_$(ENTRY_FN).elf
+ifeq ($(ARCH)$(BOOTSTRAP_DO_UEFI),amd64)
+INSTALL_FILES += bootstrap32.elf
+BOOTSTRAP_LINK_SOURCE = bootstrap32.elf
+else
+BOOTSTRAP_LINK_SOURCE = $(BOOTSTRAP_ELF_NAME)
+endif
+
+ifeq ($(BOOTSTRAP_DO_UEFI),y)
+INSTALL_FILES += bootstrap_$(ENTRY_FN).efi bootstrap.efi
+endif
+
+$(od)bootstrap_$(ENTRY_FN): $(od)$(BOOTSTRAP_LINK_SOURCE)
+ $(VERBOSE)$(LN) -f $< $@
+
+$(od)bootstrap_$(ENTRY_FN).elf: $(od)$(BOOTSTRAP_LINK_SOURCE)
+ $(VERBOSE)$(LN) -f $< $@
+
+$(od)bootstrap_$(ENTRY_FN).%: $(od)bootstrap.%
+ $(VERBOSE)$(LN) -f $< $@
+
+ ifeq ($(ARCH),$(filter $(ARCH),arm ppc32))
+ BID_POST_PROG_LINK_MSG_$(od)$(BOOTSTRAP_ELF_NAME) = echo -e " ==> Post-processing $@"
+ BID_POST_PROG_LINK_$(od)$(BOOTSTRAP_ELF_NAME) = \
+ $(VERBOSE)LANG=C $(NM) -C $@ | \
+ LANG=C $(GREP) -E ' D __PLATFORMS_(BEGIN|END)$$' | \
+ (read a i; read b i; \
+ if [ "$$a" = "$$b" ]; then \
+ echo -e "\nERROR: Missing at least one platform instantiation.\n"; \
+ $(RM) $@; \
+ exit 1; \
+ fi ) || exit 1; \
+ $(if $(BOOTSTRAP_NO_STRIP),,$(STRIP) $@)
+
+ ifneq ($(BOOTSTRAP_DO_RAW_IMAGE)$(BOOTSTRAP_DO_UIMAGE),)
+ BOOTSTRAP_RAW := $(od)bootstrap.raw
+ INSTALL_FILES += bootstrap.raw bootstrap_$(ENTRY_FN).raw
+ ifneq ($(BOOTSTRAP_DO_UIMAGE),)
+ ifneq ($(shell command -v $(MKIMAGE)),)
+ BOOTSTRAP_UIMAGE := $(od)bootstrap.uimage
+ INSTALL_FILES += bootstrap.uimage bootstrap_$(ENTRY_FN).uimage
+ else
+ $(error mkimage($(MKIMAGE)) host tool missing, cannot build bootstrap.uimage)
+ endif
+ endif
+ endif
+ endif
+
+ifneq ($(ENTRY),auto-build-entry)
+all:: $(addprefix $(IMAGES_DIR)/,$(INSTALL_FILES))
+ $(VERBOSE)echo " Image size(s) in bytes:"
+ $(VERBOSE)for f in $(filter bootstrap_$(ENTRY_FN).elf bootstrap.raw bootstrap.uimage, $(INSTALL_FILES)); do \
+ find $(if $(od),$(od),.) -name $$f -printf " %30f: %s\n"; \
+ done
+ $(if $(LDFLAGS_bootstrap.elf),$(VERBOSE)echo " Start address: $(patsubst --defsym=__executable_start=%,%,$(LDFLAGS_bootstrap.elf))")
+ $(VERBOSE)echo " --> Build-Nr: $$(cat .build_nr)"
+
+# install images into easy to reach directory in build dir
+$(IMAGES_DIR)/%: $(od)%
+ $(VERBOSE)echo " ==> Installing $< in image directory"
+ $(VERBOSE)(cd $(dir $@) && $(LN) -sf $(if $(od),,$(PWD)/)$<)
+endif # !auto-build-entry
+
+else
+ INSTALL_FILES = bootstrap
+endif # ENTRY
+
+ifneq ($(REALMODE_LOADING),0)
+CPPFLAGS += -DREALMODE_LOADING -DSINGLE_SECTION
+# don't install bootstrap_$(ENTRY_FN).elf
+INSTALL_FILES = bootstrap.load
+MOD_ADDR = 0x00150000
+endif
+
+ifneq ($(COMPRESS),0)
+SRC_C += uncompress.c gunzip.c
+CFLAGS_gunzip.c := -fno-strict-aliasing
+CPPFLAGS += -DCOMPRESS
+SPARSE_ELF := n
+endif
+
+ifeq ($(SPARSE_ELF),y)
+CPPFLAGS += -DPLACE_MODULES_AT_MODADDR
+endif
+
+ifneq ($(RAM_SIZE_MB),)
+CPPFLAGS += -DRAM_SIZE_MB=$(RAM_SIZE_MB)
+endif
+
+CXXFLAGS += -fno-rtti -fno-exceptions
+CXXFLAGS += $(call checkcxx,-fno-threadsafe-statics)
+
+ifneq ($(BUILD_MOD_CMD),)
+ ifeq ($(filter clean cleanall,$(MAKECMDGOALS)),)
+
+processing-of-module-list-failed:
+ @echo
+ @echo " Processing of $(BOOTSTRAP_MODULES_LIST) failed!"
+ @echo
+ @exit 1
+
+mod.make.inc $(od)mbi_modules.bin: $(GENERAL_D_LOC) $(shell $(call BUILD_MOD_CMD,list))
+ @echo Building entry \""$(ENTRY)"\".
+ $(VERBOSE)$(call BUILD_MOD_CMD,build)
+
+ -include mod.make.inc
+ BOOTSTRAP_LD_dep += mod.make.inc
+ STARTUP_C_dep := mod.make.inc
+ OBJS_$(od)$(BOOTSTRAP_ELF_NAME) += $(MODULE_OBJECT_FILES)
+ endif
+
+ CPPFLAGS += -DIMAGE_MODE
+endif
+
+CPPFLAGS += -DMODADDR=$(MOD_ADDR)
+
+LIBS =
+L4_LIBS = $(DRV_LIBS) $(BOOTSTRAP_L4_LIBS)
+L4_LIBS += $(GCCLIB) $(EXTRA_LIBS)
+
+all:: $(BOOTSTRAP_RAW)
+
+# image for use with pxelinux
+bootstrap.load: $(TARGET_BIN) bootsect.o.img setup.o.img
+ @$(GEN_MESSAGE)
+ $(VERBOSE)objcopy -O binary -R .note -R .comment -S $< $<.load.bin
+ $(VERBOSE)cat bootsect.o.img setup.o.img $<.load.bin > $@
+
+bootsect.o.img: ARCH-x86/bootsect.S $(SRC_DIR)/Makefile $(SRC_DIR)/Make.rules
+ @$(GEN_MESSAGE)
+ $(VERBOSE)$(CC) -traditional -nostdinc -nostdlib -c $<
+ $(VERBOSE)$(LD) -m elf_i386 -Ttext 0x0 -o $@ -s --oformat binary \
+ bootsect.o
+ $(VERBOSE)chmod -x $@
+
+setup.o.img: ARCH-x86/setup.S $(SRC_DIR)/Makefile $(SRC_DIR)/Make.rules
+ @$(GEN_MESSAGE)
+ $(VERBOSE)$(CC) -traditional -nostdinc -nostdlib -DARCH_$(ARCH) -c $<
+ $(VERBOSE)$(LD) -m elf_i386 -Ttext 0x0 -o $@ -s --oformat binary \
+ -e begtext setup.o
+ $(VERBOSE)dd if=/dev/zero bs=1 count=$$((3072 - `wc -c < setup.o.img`)) >> setup.o.img 2> /dev/null
+ $(VERBOSE)chmod -x $@
+
+# raw version without ELF, primarily useful for ARM
+$(BOOTSTRAP_RAW): $(TARGET_BIN)
+ @$(GEN_MESSAGE)
+ $(VERBOSE)cp $< $@.tmp
+ $(VERBOSE)$(OBJCOPY) -O binary $@.tmp $@
+ $(VERBOSE)chmod -x $@
+ $(VERBOSE)$(RM) $@.tmp
+
+%.gzip: %
+ gzip -c9 $^ > $@
+
+%.bzip2: %
+ bzip2 -c9 $^ > $@
+
+%.none: %
+ ln -sf $^ $@
+
+MKIMAGE_ARCH = $(if $(filter ppc32,$(ARCH)),ppc,$(ARCH))
+
+# u-boot image, based on raw-version
+$(BOOTSTRAP_UIMAGE): $(BOOTSTRAP_RAW).$(BOOTSTRAP_UIMAGE_COMPRESSION)
+ @$(GEN_MESSAGE)
+ @# mkimage writes the same file which does not play well with hardlinks
+ $(VERBOSE)$(RM) -f $@
+ $(VERBOSE)$(MKIMAGE) -e $(call default_reloc,$(ARCH)) \
+ -a $(call default_reloc,$(ARCH)) -A $(MKIMAGE_ARCH) \
+ -C $(BOOTSTRAP_UIMAGE_COMPRESSION) \
+ -n "L4 Image #$$(cat .build_nr)" \
+ -d $^ $@
+
+$(TARGET): $(LDSCRIPT) $(OBJS_$(TARGET))
+
+
+increment_build_nr = \
+ $(shell if [ -e .build_nr ]; then \
+ nr=$$(($$(cat .build_nr) + 1)); \
+ else \
+ nr=1; \
+ fi; \
+ echo $$nr > .build_nr; echo $$nr)
+
+
+startup.o: $(STARTUP_C_dep)
+startup.o: CPPFLAGS += -DBUILD_DATE="\"$(shell date)\"" -DBUILD_NR=\"$(call increment_build_nr)\"
+
+$(LDSCRIPT): $(LDSCRIPT).in $(GENERAL_D_LOC) $(BOOTSTRAP_LD_dep)
+ @$(GEN_MESSAGE)
+ $(VERBOSE)$(CROSS_COMPILE)cpp -P $(CPPFLAGS) -DLINKADDR=$(strip $(call default_reloc,$(ARCH))) $< $@;
+
+clean::
+ $(VERBOSE)$(RM) mod.make.inc mod*.bin mbi_modules.bin $(LDSCRIPT)
+ $(VERBOSE)$(RM) setup.o.img bootsect.o.img
+ $(VERBOSE)$(RM) mod*.bin
+ $(VERBOSE)$(RM) $(SRC32_C:.c=.o32) $(SRC32_S:.S=.o32)
+ $(VERBOSE)$(RM) .redo-change-tracker
+
+cleanall::
+ $(VERBOSE)$(RM) $(od)bootstrap_* $(od)bootstrap.*
+
+bootstrap.efi: bootstrap.elf
+ $(OBJCOPY) -S -j .text -j .rodata -j .reloc -j .dynsym -j .dynstr -j .rel.dyn \
+ -j .data \
+ -j .data.module_info -j .dynamic -j .rela.dyn -j .rela.plt -j .reloc \
+ -j .bss -j .module_data \
+ --target=$(EFI_BIN_FMT) $< $@
+
+ifeq ($(ARCH),amd64)
+
+vpath %.c $(SRC_DIR)/ARCH-amd64
+vpath %.S $(SRC_DIR)/ARCH-amd64
+vpath %.c $(SRC_DIR)/ARCH-amd64/boot32
+vpath %.S $(SRC_DIR)/ARCH-amd64/boot32
+vpath bootstrap.ld.in $(SRC_DIR)/ARCH-x86
+
+SRC32_C = boot_cpu.c boot_kernel.c load_elf.c minilibc_support.c
+SRC32_S = boot.S boot_idt.S
+OBJ32 = $(SRC32_S:.S=.o32) $(SRC32_C:.c=.o32)
+CC32 = $(filter-out -m64, $(CC)) -m32
+CFLAGS32 = $(filter-out -m64, $(CFLAGS) $(CFLAGS_$(ARCH))) -m32 $(GCCNOSTACKPROTOPT)
+
+$(OBJ_DIR)/ARCH-amd64/libc32/OBJ-$(ARCH)_$(CPU)/libc32.a: FORCE
+ $(VERBOSE)$(MAKE) O=$(OBJ_BASE) -C $(SRC_DIR)/ARCH-amd64/libc32
+
+bootstrap32.elf: $(OBJ32) bootstrap32.bin $(SRC_DIR)/ARCH-amd64/boot32/bootstrap32.ld $(OBJ_DIR)/ARCH-amd64/libc32/OBJ-$(ARCH)_$(CPU)/libc32.a
+ @$(LINK_MESSAGE)
+ $(VERBOSE)$(CC32) -o $@ -nostdlib -static \
+ -Wl,-T,$(SRC_DIR)/ARCH-amd64/boot32/bootstrap32.ld,--gc-sections $^ -lgcc
+ $(VERBOSE)chmod 755 $@
+
+bootstrap: bootstrap32.elf
+ $(VERBOSE)$(LN) -f $^ $@
+
+bootstrap32.bin: $(BOOTSTRAP_ELF_NAME)
+ @$(GEN_MESSAGE)
+ $(VERBOSE)$(OBJCOPY) -S $< bootstrap64.bin
+ $(VERBOSE)chmod -x bootstrap64.bin
+ $(VERBOSE)$(OBJCOPY) -B i386 -I binary -O elf32-i386 bootstrap64.bin $@
+
+%.o32: %.c $(SRC_DIR)/Makefile $(SRC_DIR)/Make.rules
+ @$(COMP_MESSAGE)
+ $(VERBOSE)$(CC32) -o $@ -c $(DEPEND_FLAG) \
+ $(CPPFLAGS) $(CFLAGS32) $(call absfilename,$<)
+
+%.o32: %.S $(SRC_DIR)/Makefile $(SRC_DIR)/Make.rules
+ @$(COMP_MESSAGE)
+ $(VERBOSE)$(CC32) -o $@ -c $(DEPEND_FLAG) \
+ $(CPPFLAGS) $(CFLAGS32) $(call absfilename,$<)
+
+clean cleanall::
+ $(VERBOSE)PWD=$(call absfilename,$(SRC_DIR)/ARCH-amd64/libc32) \
+ $(MAKE) -C $(SRC_DIR)/ARCH-amd64/libc32 $@
+
+else
+bootstrap: $(BOOTSTRAP_ELF_NAME)
+ $(VERBOSE)$(LN) -f $^ $@
+endif
+
+INSTALL_TARGET := $(if $(od),,$(INSTALL_FILES))
--- /dev/null
+#edited by coon 10 apr
+#REALMODE_LOADING=1
+#JAILHOUSE
+#IMAGE_MODE
\ No newline at end of file
--- /dev/null
+PKGDIR ?= ../..
+L4DIR ?= $(PKGDIR)/../..
+
+SYSTEMS = $(SYSTEMS_PLAIN)
+
+include $(L4DIR)/mk/prog.mk
--- /dev/null
+
+# ARM platforms
+SUPPORT_CC_arm-sa1000 := platform/sa1000.cc
+SUPPORT_CC_arm-pxa := platform/pxa.cc
+SUPPORT_CC_arm-integrator := platform/integrator.cc
+SUPPORT_CC_arm-rv := platform/rv.cc
+SUPPORT_CC_arm-rv_pbx := platform/rv.cc
+SUPPORT_CC_arm-rv_vexpress := platform/rv_vexpress.cc
+SUPPORT_CC_arm-rv_vexpress_a15 := platform/rv_vexpress.cc
+SUPPORT_CC_arm-omap3evm := platform/omap.cc
+SUPPORT_CC_arm-omap3_am33xx := platform/omap.cc
+SUPPORT_CC_arm-beagleboard := platform/omap.cc
+SUPPORT_CC_arm-pandaboard := platform/omap.cc
+SUPPORT_CC_arm-omap5 := platform/omap.cc
+SUPPORT_CC_arm-tegra2 := platform/tegra2.cc
+SUPPORT_CC_arm-tegra3 := platform/tegra3.cc
+SUPPORT_CC_arm-imx21 := platform/imx.cc
+DEFAULT_RELOC_arm-imx21 := 0x00200000 # because of blob
+SUPPORT_CC_arm-imx35 := platform/imx.cc
+SUPPORT_CC_arm-imx51 := platform/imx.cc
+SUPPORT_CC_arm-imx6 := platform/imx.cc
+SUPPORT_CC_arm-om := platform/om.cc
+SUPPORT_CC_arm-kirkwood := platform/kirkwood.cc
+SUPPORT_CC_arm-rpi_a := platform/rpi.cc
+SUPPORT_CC_arm-rpi_b := platform/rpi.cc
+SUPPORT_CC_arm-exynos4 := platform/exynos.cc
+SUPPORT_CC_arm-exynos5 := platform/exynos.cc
+SUPPORT_CC_arm-zedboard := platform/zynq.cc
+SUPPORT_CC_arm-parallella := platform/zynq.cc
+SUPPORT_CC_arm-cubieboard2 := platform/sunxi.cc
+SUPPORT_CC_arm-armada38x := platform/armada38x.cc
+
+# PPC
+SUPPORT_CC_ppc32-mpc5200 := platform/mpc5200.cc
+
+# Sparc
+SUPPORT_CC_sparc-leon3 := platform/leon3.cc
+
+# x86
+ifneq ($(BOOTSTRAP_DO_UEFI),y)
+SUPPORT_CC_x86-pc := platform/x86_pc.cc
+SUPPORT_CC_amd64-pc := platform/x86_pc.cc
+else
+SUPPORT_CC_x86-pc := platform/x86_efi_pc.cc
+SUPPORT_CC_amd64-pc := platform/x86_efi_pc.cc
+endif
--- /dev/null
+
+bootstrap supports different boot modi.
+
+For x86:
+
+ 1)
+ boostrap is started by a multiboot compliant bootloader and modules are
+ attached as multiboot modules. GRUB example:
+
+ kernel bootstrap arg1 args2 ...
+ module kernel
+ module sigma0
+ module roottask
+ module task1
+ ...
+
+ 2)
+ bootstrap is started by a multiboot compliant bootloader but includes
+ all modules by itself. GRUB example:
+
+ kernel bootstrap_hello args...
+
+ For module specifications looks into modules.list
+
+ 3)
+ bootstrap can boot from real-mode, esp. with pxelinux, i.e. it can be
+ booted via PXE. For that it also needs include all images.
+ This should also work with syslinux (e.g. from CDs/DVDs). (Note, grub
+ can also read is9660 filesystems.)
+
+ 4)
+ bootstrap starts from protected mode but isn't started by a multiboot
+ compliant loader. Also needs to include all modules.
+
+For arm:
+
+ Just the single image mode, i.e. all modules packed into bootstrap.
+ Anything else doesn't make any sense (currently).
+
+
+Generating bootstrap in single-image-mode:
+
+ Call make with E=entryname, e.g.
+
+ $ make E=hello
+
+
+Local customization:
+
+ You can put a Makeconf.local file right into this directory
+ (bootstrap/server/src) where you can specify your own search paths etc.
+ Note that it is encouraged to have your local configuration in src/conf
+ rather than in this bootstrap directory.
+
+ Makeconf.local could look like this:
+
+ BOOTSTRAP_SEARCH_PATH_x86 := ../stuff:/home/joe/dev/l4/kernel/fiasco/build-ia32
+
+ KERN_ARM := build-arm
+
+ ifneq ($(PXA),)
+ KERN_ARM := build-pxa
+ ARM_DRV_TYPE = pxa
+ endif
+
+ KERN_PATH := /home/joe/dev/l4/kernel/fiasco/$(KERN_ARM)
+ BOOTSTRAP_SEARCH_PATH_arm = ../stuff:$(KERN_PATH):../../../../../bin/arm_sa
+
+ BOOTSTRAP_SEARCH_PATH = $(BOOTSTRAP_SEARCH_PATH_$(ARCH))
+
--- /dev/null
+/*
+ * (c) 2008-2009 Frank Mehnert <fm3@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include <l4/util/irq.h>
+#include "base_critical.h"
+
+static l4_umword_t flags;
+static l4_umword_t entry_count;
+
+void
+base_critical_enter(void)
+{
+ if (entry_count == 0)
+ {
+ l4util_flags_save(&flags);
+ l4util_cli();
+ }
+ entry_count++;
+}
+
+void
+base_critical_leave(void)
+{
+ entry_count--;
+ if (entry_count == 0)
+ l4util_flags_restore(&flags);
+}
+
--- /dev/null
+/*
+ * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ * Frank Mehnert <fm3@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#ifndef BASE_CRITICAL_H
+#define BASE_CRITICAL_H
+
+#include <l4/sys/compiler.h>
+
+EXTERN_C_BEGIN
+
+void base_critical_enter(void);
+void base_critical_leave(void);
+
+EXTERN_C_END
+
+#endif
--- /dev/null
+#include "support.h"
+#include "panic.h"
+#include <cassert>
+#include "mod_info.h"
+#ifdef COMPRESS
+#include "uncompress.h"
+#endif
+
+static char const Mod_reg[] = ".Module";
+char const *const Boot_modules::Mod_reg = ::Mod_reg;
+
+// get c if it is printable '.' else
+static char
+get_printable(int c)
+{
+ if (c < 32 || c >= 127)
+ return '.';
+ return c;
+}
+Region
+Boot_modules::mod_region(unsigned index, l4_addr_t start, l4_addr_t size,
+ Region::Type type)
+{
+ return Region::start_size(start, size, ::Mod_reg,
+ type, index);
+}
+
+void
+Boot_modules::merge_mod_regions()
+{
+ Region_list *regions = mem_manager->regions;
+ for (Region *r = regions->begin(); r != regions->end(); ++r)
+ {
+ if (r->name() == ::Mod_reg)
+ r->sub_type(0);
+ }
+
+ regions->optimize();
+}
+
+
+/**
+ * \brief move a boot module from src to dest.
+ * \param i The module index
+ * \param dest The destination address
+ * \param src The source address
+ * \param size The size of the module in bytes
+ * \param overlap_check if true check for overlapping regions at
+ * the destination.
+ *
+ * The src and dest buffers may overlap, at the destination set size is
+ * rounded to the next page boundary.
+ */
+void
+Boot_modules::_move_module(unsigned i, void *_dest,
+ void const *_src, unsigned long size,
+ bool overlap_check)
+{
+ char *dest = (char *)_dest;
+ char const *src = (char const *)_src;
+
+ if (src == dest)
+ {
+ mem_manager->regions->add(Region::n(dest, dest + size,
+ ::Mod_reg, Region::Root, i));
+ return;
+ }
+
+ auto p = Platform_base::platform;
+ char const *vsrc = (char const *)p->to_virt((l4_addr_t)src);
+ char *vdest = (char *)p->to_virt((l4_addr_t)dest);
+
+ if (Verbose_load)
+ {
+ unsigned char c[5];
+ c[0] = get_printable(vsrc[0]);
+ c[1] = get_printable(vsrc[1]);
+ c[2] = get_printable(vsrc[2]);
+ c[3] = get_printable(vsrc[3]);
+ c[4] = 0;
+ printf(" moving module %02d { %lx, %lx } (%s) -> { %lx - %lx } [%ld]\n",
+ i, (unsigned long)src, (unsigned long)src + size - 1, c,
+ (unsigned long)dest, (unsigned long)dest + size - 1, size);
+
+ for (int a = 0; a < 0x100; a += 4)
+ printf("%08x%s", *(unsigned *)(vsrc + a), (a % 32 == 28) ? "\n" : " ");
+ printf("\n");
+ }
+ else
+ printf(" moving module %02d { %lx-%lx } -> { %lx-%lx } [%ld]\n",
+ i, (unsigned long)src, (unsigned long)src + size - 1,
+ (unsigned long)dest, (unsigned long)dest + size - 1, size);
+
+ if (!mem_manager->ram->contains(dest))
+ panic("Panic: Would move outside of RAM");
+
+ if (overlap_check)
+ {
+ Region *overlap = mem_manager->regions->find(dest);
+ if (overlap)
+ {
+ printf("ERROR: module target [%p-%p) overlaps\n",
+ dest, dest + size - 1);
+ overlap->vprint();
+ mem_manager->regions->dump();
+ panic("cannot move module");
+ }
+ }
+ memmove(vdest, vsrc, size);
+ char *x = vdest + size;
+ memset(x, 0, l4_round_page(x) - x);
+ mem_manager->regions->add(Region::n(dest, dest + size,
+ ::Mod_reg, Region::Root, i));
+}
+
+/// sorter data for up to 256 modules (stores module indexes)
+static unsigned short mod_sorter[256];
+/// the first unused entry of the sorter
+static unsigned short const *mod_sorter_end = mod_sorter;
+
+/// add v to the sorter (using insert sort)
+template< typename CMP > void
+mod_insert_sorted(unsigned short v, CMP const &cmp)
+{
+ enum { Max_mods = sizeof(mod_sorter) / sizeof(mod_sorter[0]) };
+
+ if (mod_sorter_end >= mod_sorter + Max_mods)
+ panic("too much modules for module sorter");
+
+ unsigned short *i = mod_sorter;
+ unsigned short const *const e = mod_sorter_end;
+
+ for (; i < e; ++i)
+ {
+ if (cmp(v, *i))
+ {
+ memmove(i + 1, i, (e - i) * sizeof(*i));
+ break;
+ }
+ }
+ *i = v;
+ ++mod_sorter_end;
+}
+
+/// Compare start addresses for two modules
+struct Mbi_mod_cmp
+{
+ Boot_modules *m;
+ Mbi_mod_cmp(Boot_modules *m) : m(m) {}
+ bool operator () (unsigned l, unsigned r) const
+ { return m->module(l, false).start < m->module(r, false).start; }
+};
+
+/// calculate the total size of all modules (rounded to the next p2align)
+static unsigned long
+calc_modules_size(Boot_modules *mbi, unsigned p2align,
+ unsigned min = 0, unsigned max = ~0U)
+{
+ unsigned long s = 0;
+ unsigned cnt = mbi->num_modules();
+ for (unsigned i = min; i < max && i < cnt; ++i)
+ s += l4_round_size(mbi->module(i).size(), p2align);
+
+ return s;
+}
+
+
+/**
+ * Move modules to another address.
+ *
+ * Source and destination regions may overlap.
+ */
+void
+Boot_modules::move_modules(unsigned long modaddr)
+{
+ unsigned count = num_modules();
+
+ // Remove regions for module contents from region list.
+ // The memory for the boot modules is marked as reserved up to now,
+ // however to not collide with the ELF binaries to be loaded we drop those
+ // regions here and add new reserved regions in move_modules() afterwards.
+ // NOTE: we must be sure that we do not need to allocate any memory from here
+ // to move_modules()
+ for (Region *i = mem_manager->regions->begin();
+ i < mem_manager->regions->end();)
+ if (i->name() == ::Mod_reg)
+ i = mem_manager->regions->remove(i);
+ else
+ ++i;
+
+ printf(" Moving up to %d modules behind %lx\n", count, modaddr);
+ unsigned long req_size = calc_modules_size(this, L4_PAGESHIFT);
+
+ // find a spot to insert the modules
+ mem_manager->ram->sort();
+ char *to = (char *)mem_manager->find_free_ram(req_size, modaddr);
+ if (!to)
+ {
+ printf("fatal: could not find free RAM region for modules\n"
+ " need %lx bytes above %lx\n", req_size, modaddr);
+ mem_manager->ram->dump();
+ mem_manager->regions->dump();
+ exit (5);
+ }
+
+ // sort the modules according to the start address
+ for (unsigned i = 0; i < count; ++i)
+ mod_insert_sorted(i, Mbi_mod_cmp(this));
+
+ // move modules around ...
+ // The goal is to move all modules in a contiguous region in memory.
+ // The idea is to keep the order of the modules in memory and compact them
+ // into our target region. Therefore we split the modules into two groups.
+ // The first group needs to be moved to higher memory addresses to get to
+ // the target location and the second group needs to be moved backwards.
+
+ // Let's find the first module that needs to be moved backwards and record
+ // target address for this module.
+ unsigned end_fwd; // the index of the first module that needs to move backwards
+ char *cursor = to; // the target address for the first backwards module
+ for (end_fwd = 0; end_fwd < count; ++end_fwd)
+ {
+ Module mod = module(mod_sorter[end_fwd]);
+ if (cursor < mod.start)
+ break;
+
+ cursor += l4_round_page(mod.size());
+ }
+
+ // end_fwd is now the index of the first module that needs to move backwards
+ // cursor cursor is now the target address for the first backwards module
+
+ // move modules forwards, in reverse order so that overlapping is handled
+ // properly
+ char *end_fwd_addr = cursor;
+ for (unsigned i = end_fwd; i > 0; --i)
+ {
+ Module mod = module(mod_sorter[i - 1]);
+ end_fwd_addr -= l4_round_page(mod.size());
+ move_module(mod_sorter[i - 1], end_fwd_addr);
+ }
+
+ // move modules backwards, in normal order so that overlapping is handled
+ // properly
+ for (unsigned i = end_fwd; i < count; ++i)
+ {
+ Module mod = module(mod_sorter[i]);
+ move_module(mod_sorter[i], cursor);
+ cursor += l4_round_page(mod.size());
+ }
+
+ merge_mod_regions();
+}
+
+
+/*
+ * Code for IMAGE_MODE, modules are linked into bootstrap
+ */
+#ifdef IMAGE_MODE
+
+/// array of all module headers
+extern Mod_info _module_info_start[];
+/// the end of the module headers
+extern Mod_info _module_info_end[];
+
+namespace {
+/*
+ * Helper functions for modules
+ */
+
+/// number of linked modules
+static inline unsigned _num_modules()
+{ return _module_info_end - _module_info_start; }
+
+static inline char const *mod_cmdline(Mod_info const *mod)
+{ return (char const *)(l4_addr_t)mod->cmdline; }
+
+static inline char const *mod_name(Mod_info const *mod)
+{ return (char const *)(l4_addr_t)mod->name; }
+
+static inline char const *mod_start(Mod_info const *mod)
+{ return mod->start; }
+
+static inline Region mod_region(Mod_info const *mod, bool round = false,
+ Region::Type type = Region::Boot)
+{
+ unsigned long sz = mod->size;
+ if (round)
+ sz = l4_round_page(sz);
+ return Region::array(mod_start(mod), sz,
+ ::Mod_reg,
+ type, mod - _module_info_start);
+}
+
+#ifdef COMPRESS // only used with compression
+static bool
+drop_mod_region(Mod_info const *mod)
+{
+ // remove the module region for now
+ for (Region *r = mem_manager->regions->begin();
+ r != mem_manager->regions->end();)
+ {
+ if (r->name() == ::Mod_reg
+ && r->sub_type() == mod - _module_info_start)
+ {
+ mem_manager->regions->remove(r);
+ return true;
+ }
+ else
+ ++r;
+ }
+
+ return false;
+}
+#endif
+
+static inline char const *mod_md5compr(Mod_info const *mod)
+{ return (char const *)(l4_addr_t)mod->md5sum_compr; }
+
+static inline char const *mod_md5(Mod_info const *mod)
+{ return (char const *)(l4_addr_t)mod->md5sum_uncompr; }
+
+static inline bool mod_compressed(Mod_info const *mod)
+{ return mod->size != mod->size_uncompressed; }
+
+static inline void
+print_mod(Mod_info const *mod)
+{
+ unsigned index = mod - _module_info_start;
+ printf(" mod%02u: %8p-%8p: %s\n",
+ index, mod_start(mod), mod_start(mod) + mod->size,
+ mod_name(mod));
+}
+
+#ifdef DO_CHECK_MD5
+#include <bsd/md5.h>
+
+static void check_md5(const char *name, u_int8_t *start, unsigned size,
+ const char *md5sum)
+{
+ MD5_CTX md5ctx;
+ unsigned char digest[MD5_DIGEST_LENGTH];
+ char s[MD5_DIGEST_STRING_LENGTH];
+ static const char hex[] = "0123456789abcdef";
+ int j;
+
+ printf(" Checking checksum of %s ... ", name);
+
+ MD5Init(&md5ctx);
+ MD5Update(&md5ctx, start, size);
+ MD5Final(digest, &md5ctx);
+
+ for (j = 0; j < MD5_DIGEST_LENGTH; j++)
+ {
+ s[j + j] = hex[digest[j] >> 4];
+ s[j + j + 1] = hex[digest[j] & 0x0f];
+ }
+ s[j + j] = '\0';
+
+ if (strcmp(s, md5sum))
+ panic("\nmd5sum mismatch");
+ else
+ printf("Ok.\n");
+}
+#else // DO_CHECK_MD5
+static inline void check_md5(const char *, u_int8_t *, unsigned, const char *)
+{}
+#endif // ! DO_CHECK_MD5
+
+#ifdef COMPRESS
+static void
+decompress_mod(Mod_info *mod, l4_addr_t dest, Region::Type type = Region::Boot)
+{
+ unsigned long dest_size = mod->size_uncompressed;
+ if (!dest)
+ panic("fatal: cannot decompress module: %s (no memory)\n",
+ mod_name(mod));
+
+ if (!mem_manager->ram->contains(Region::n(dest, dest + dest_size)))
+ panic("fatal: module %s does not fit into RAM", mod_name(mod));
+
+ l4_addr_t image =
+ (l4_addr_t)decompress(mod_name(mod), (void*)mod_start(mod),
+ (void*)dest, mod->size, mod->size_uncompressed);
+ if (image != dest)
+ panic("fatal cannot decompress module: %s (decompression error)\n",
+ mod_name(mod));
+
+ drop_mod_region(mod);
+
+ mod->start = (char *)dest;
+ mod->size = mod->size_uncompressed;
+ mem_manager->regions->add(mod_region(mod, true, type));
+}
+#endif // COMPRESS
+}
+
+
+void
+Boot_modules_image_mode::reserve()
+{
+ for (Mod_info *m = _module_info_start; m != _module_info_end; ++m)
+ {
+ m->start = (char const *)Platform_base::platform->to_phys((l4_addr_t)m->start);
+ mem_manager->regions->add(::mod_region(m));
+ }
+}
+
+
+/// Get module at index (decompress if needed)
+Boot_modules_image_mode::Module
+Boot_modules_image_mode::module(unsigned index, bool uncompress) const
+{
+ // want access to the module, if we have compression we need to decompress
+ // the module first
+ Mod_info *mod = _module_info_start + index;
+#ifdef COMPRESS
+ // we currently assume a module as compressed when the size != size_compressed
+ if (uncompress && mod_compressed(mod))
+ {
+ check_md5(mod_name(mod), (u_int8_t *)mod_start(mod),
+ mod->size, mod_md5compr(mod));
+
+ unsigned long dest_size = l4_round_page(mod->size_uncompressed);
+ decompress_mod(mod, mem_manager->find_free_ram_rev(dest_size));
+
+ check_md5(mod_name(mod), (u_int8_t *)mod_start(mod),
+ mod->size, mod_md5(mod));
+ }
+#else
+ (void)uncompress;
+#endif
+ Module m;
+ m.start = mod->start;
+ m.end = mod->start + mod->size;
+ m.cmdline = mod_name(mod);
+ return m;
+}
+
+unsigned
+Boot_modules_image_mode::num_modules() const
+{
+ return _num_modules();
+}
+
+#ifdef COMPRESS
+static void
+decomp_move_mod(Mod_info *mod, char *destbuf)
+{
+ if (mod_compressed(mod))
+ decompress_mod(mod, (l4_addr_t)destbuf, Region::Root);
+ else
+ {
+ memmove(destbuf, mod_start(mod), mod->size_uncompressed);
+#if 0 // cannot simply zero this out, this might overlap with
+ // the next module to decompress
+ l4_addr_t dest_size = l4_round_page( mod->size_uncompressed);
+
+ if (dest_size > mod->size_uncompressed)
+ memset((void *)(destbuf + mod->size_uncompressed), 0,
+ dest_size - mod->size_uncompressed);
+#endif
+ drop_mod_region(mod);
+ mod->start = destbuf;
+ mem_manager->regions->add(mod_region(mod, true, Region::Root));
+ }
+ print_mod(mod);
+}
+
+void
+Boot_modules_image_mode::decompress_mods(unsigned mod_count, unsigned skip,
+ l4_addr_t total_size, l4_addr_t mod_addr)
+{
+ Mod_info *mod_info = _module_info_start;
+ Region_list *regions = mem_manager->regions;
+ assert (mod_count > skip);
+
+ printf("Compressed modules:\n");
+ for (Mod_info const *mod = mod_info; mod != _module_info_end;
+ ++mod)
+ if (mod_compressed(mod))
+ print_mod(mod);
+
+ // sort the modules according to the start address
+ for (unsigned i = skip; i < mod_count; ++i)
+ mod_insert_sorted(i, Mbi_mod_cmp(this));
+
+ // possibly decompress directly behind the end of the first module
+ // We can do this, when we start decompression from the last module
+ // and ensure that no decompressed module overlaps its compressed data
+ Mod_info const *m0 = &mod_info[mod_sorter[0]];
+ char const *rdest = l4_round_page(mod_start(m0) + m0->size);
+ char const *ldest = l4_trunc_page(mod_start(m0) - m0->size_uncompressed);
+
+ // try to find a free spot for decompressing the modules
+ char *destbuf = (char *)mem_manager->find_free_ram(total_size, mod_addr);
+ bool fwd = true;
+
+ if (!destbuf || destbuf > rdest)
+ {
+ // we found free memory behind the compressed modules, we try to find a
+ // spot overlapping with the compressed modules, to safe contiguous
+ // memory
+ char const *rpos = rdest;
+ char const *lpos = ldest;
+ for (unsigned i = 0; i < mod_count - skip; ++i)
+ {
+ Mod_info const *mod = &mod_info[mod_sorter[i]];
+ char const *mstart = mod_start(mod);
+ char const *mend = mod_start(mod) + mod->size;
+ // remove the module region for now
+ for (Region *r = regions->begin(); r != regions->end();)
+ {
+ if (r->name() == ::Mod_reg && r->sub_type() == mod - mod_info)
+ r = regions->remove(r);
+ else
+ ++r;
+ }
+
+ if (rpos < mend)
+ {
+ l4_addr_t delta = l4_round_page(mend) - rpos;
+ rpos += delta;
+ rdest += delta;
+ }
+
+ if (ldest && lpos + mod->size_uncompressed > mstart)
+ {
+ l4_addr_t delta = l4_round_page(lpos + mod->size_uncompressed - mstart);
+ if ((l4_addr_t)ldest > delta)
+ {
+ lpos -= delta;
+ ldest -= delta;
+ }
+ else
+ ldest = 0;
+ }
+
+ rpos += l4_round_page(mod->size_uncompressed);
+ lpos += l4_round_page(mod->size_uncompressed);
+ }
+
+ Region dest = Region::array(ldest, total_size);
+ destbuf = const_cast<char *>(ldest);
+ fwd = true;
+ if (!ldest || !mem_manager->ram->contains(dest) || regions->find(dest))
+ {
+ printf(" cannot decompress at %p, try %p\n", ldest, rdest);
+ dest = Region::array(rdest, total_size); // try the move behind version
+ destbuf = const_cast<char *>(rdest);
+ fwd = false;
+
+ if (!mem_manager->ram->contains(dest) || regions->find(dest))
+ {
+ destbuf = (char *)mem_manager->find_free_ram(total_size, (l4_addr_t)rdest);
+ printf(" cannot decompress at %p, use %p\n", rdest, destbuf);
+ }
+ }
+ }
+
+ if (!destbuf)
+ panic("fatal: cannot find memory to decompress modules");
+
+ printf("Uncompressing modules (modaddr = %p (%s)):\n", destbuf,
+ fwd ? "forwards" : "backwards");
+ if (!fwd)
+ {
+ // advance to last module end
+ destbuf += total_size;
+
+ for (unsigned i = mod_count - skip; i > 0; --i)
+ {
+ Mod_info *mod = _module_info_start + mod_sorter[i - 1];
+ unsigned long dest_size = l4_round_page(mod->size_uncompressed);
+ destbuf -= dest_size;
+ decomp_move_mod(mod, destbuf);
+ }
+ }
+ else
+ {
+ for (unsigned i = 0; i < mod_count - skip; ++i)
+ {
+ Mod_info *mod = _module_info_start + mod_sorter[i];
+ unsigned long dest_size = l4_round_page(mod->size_uncompressed);
+ decomp_move_mod(mod, destbuf);
+ destbuf += dest_size;
+ }
+ }
+
+ // move modules 0-2 out of the way
+ for (unsigned i = 0; i < skip; ++i)
+ {
+ Mod_info *mod = _module_info_start + i;
+ Region mr = ::mod_region(mod);
+ for (Region *r = regions->begin(); r != regions->end(); ++r)
+ {
+ if (r->overlaps(mr) && r->name() != ::Mod_reg)
+ {
+ // overlaps with some non-module, assumingly an ELF region
+ // so move us out of the way
+ char *to = (char *)mem_manager->find_free_ram(mod->size);
+ if (!to)
+ {
+ printf("fatal: could not find free RAM region for module\n"
+ " need %lx bytes\n", (unsigned long)mod->size);
+ mem_manager->ram->dump();
+ regions->dump();
+ panic("\n");
+ }
+ move_module(i, to);
+ break;
+ }
+ }
+ }
+}
+#endif // COMPRESS
+
+/**
+ * Create the basic multi-boot structure in IMAGE_MODE
+ */
+l4util_mb_info_t *
+Boot_modules_image_mode::construct_mbi(unsigned long mod_addr)
+{
+ unsigned long mod_count = _num_modules();
+ unsigned long mbi_size = sizeof(l4util_mb_info_t);
+ mbi_size += sizeof(l4util_mb_mod_t) * mod_count;
+
+ enum { Skip_num_mods = 3 }; // skip fiasco, sigma0, and roottask
+ assert(mod_count >= Skip_num_mods);
+
+ for (Mod_info const *mod = _module_info_start; mod != _module_info_end;
+ ++mod)
+ mbi_size += round_wordsize(strlen(mod_cmdline(mod)) + 1);
+
+ l4util_mb_info_t *mbi = (l4util_mb_info_t *)mem_manager->find_free_ram(mbi_size);
+ if (!mbi)
+ panic("fatal: could not allocate MBI memory: %lu bytes\n", mbi_size);
+
+ Region_list *regions = mem_manager->regions;
+ regions->add(Region::start_size((l4_addr_t)mbi, mbi_size, ".mbi_rt",
+ Region::Root));
+ memset(mbi, 0, mbi_size);
+
+ l4util_mb_mod_t *mods = reinterpret_cast<l4util_mb_mod_t *>(mbi + 1);
+ char *mbi_strs = (char *)(mods + mod_count);
+
+ mbi->mods_count = mod_count;
+ mbi->flags |= L4UTIL_MB_MODS;
+ mbi->mods_addr = (l4_addr_t)mods;
+
+
+ Mod_info *const mod_info = _module_info_start;
+ unsigned long total_size = 0;
+ for (Mod_info const *mod = mod_info + Skip_num_mods;
+ mod < _module_info_end;
+ ++mod)
+ {
+ total_size += l4_round_page(mod->size_uncompressed);
+ if (mod_compressed(mod))
+ check_md5(mod_name(mod), (u_int8_t*)mod_start(mod),
+ mod->size, mod_md5compr(mod));
+ }
+
+#ifdef COMPRESS
+ if (mod_count > Skip_num_mods)
+ decompress_mods(mod_count, Skip_num_mods, total_size, mod_addr);
+ merge_mod_regions();
+#else // COMPRESS
+ move_modules(mod_addr);
+#endif // ! COMPRESS
+
+ for (unsigned i = 0; i < mod_count; ++i)
+ {
+ Mod_info const *mod = &_module_info_start[i];
+ check_md5(mod_name(mod), (u_int8_t*)mod_start(mod),
+ mod->size_uncompressed, mod_md5(mod));
+
+ if (char const *c = mod_cmdline(mod))
+ {
+ unsigned l = strlen(c) + 1;
+ mods[i].cmdline = (l4_addr_t)mbi_strs;
+ memcpy(mbi_strs, c, l);
+ mbi_strs += round_wordsize(l);
+ }
+
+ mods[i].mod_start = (l4_addr_t)mod_start(mod);
+ mods[i].mod_end = (l4_addr_t)mod_start(mod) + mod->size;
+ }
+
+ return mbi;
+}
+
+
+void
+Boot_modules_image_mode::move_module(unsigned index, void *dest,
+ bool overlap_check)
+{
+ Mod_info *mod = &_module_info_start[index];
+ unsigned long size = mod->size;
+ _move_module(index, dest, mod_start(mod), size, overlap_check);
+ mod->start = (char *)dest;
+}
+
+#endif // IMAGE_MODE
+
--- /dev/null
+#! /usr/bin/perl -W
+#
+# (c) 2008-2009 Technische Universität Dresden
+# This file is part of TUD:OS and distributed under the terms of the
+# GNU General Public License 2.
+# Please see the COPYING-GPL-2 file for details.
+#
+# Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+#
+
+use strict;
+
+BEGIN { unshift @INC, $ENV{L4DIR}.'/tool/lib'
+ if $ENV{L4DIR} && -d $ENV{L4DIR}.'/tool/lib/L4';}
+
+use Digest::MD5;
+use L4::ModList;
+
+
+my $cross_compile_prefix = $ENV{CROSS_COMPILE} || '';
+my $arch = $ENV{OPT_ARCH} || "x86";
+
+my $module_path = $ENV{SEARCHPATH} || ".";
+my $prog_objcopy = $ENV{OBJCOPY} || "${cross_compile_prefix}objcopy";
+my $prog_cc = $ENV{CC} || "${cross_compile_prefix}gcc";
+my $prog_ld = $ENV{LD} || "${cross_compile_prefix}ld";
+my $prog_cp = $ENV{PROG_CP} || "cp";
+my $prog_gzip = $ENV{PROG_GZIP} || "gzip";
+my $compress = $ENV{OPT_COMPRESS} || 0;
+my $strip = $ENV{OPT_STRIP} || 1;
+my $output_dir = $ENV{OUTPUT_DIR} || '.';
+my $make_inc_file = $ENV{MAKE_INC_FILE} || "mod.make.inc";
+my $flags_cc = $ENV{FLAGS_CC} || '';
+
+my $modulesfile = $ARGV[1];
+my $entryname = $ARGV[2];
+
+sub usage()
+{
+ print STDERR "$0 modulefile entry\n";
+}
+
+# Write a string to a file, overwriting it.
+# 1: filename
+# 2..n: Strings to write to the file
+sub write_to_file
+{
+ my $file = shift;
+
+ open(A, ">$file") || die "Cannot open $file!";
+ while ($_ = shift) {
+ print A;
+ }
+ close A;
+}
+
+sub first_word($)
+{
+ (split /\s+/, shift)[0]
+}
+
+# build object files from the modules
+sub build_obj($$$)
+{
+ my ($cmdline, $modname, $no_strip) = @_;
+ my $_file = first_word($cmdline);
+
+ my $file = L4::ModList::search_file($_file, $module_path)
+ || die "Cannot find file $_file! Used search path: $module_path";
+
+ printf STDERR "Merging image %s to %s [%dkB]\n",
+ $file, $modname, ((-s $file) + 1023) / 1024;
+ # make sure that the file isn't already compressed
+ system("$prog_gzip -dc $file > $modname.ugz 2> /dev/null");
+ $file = "$modname.ugz" if !$?;
+ system("$prog_objcopy -S $file $modname.obj 2> /dev/null")
+ if $strip && !$no_strip;
+ system("$prog_cp $file $modname.obj")
+ if $? || !$strip || $no_strip;
+ my $uncompressed_size = -s "$modname.obj";
+
+ my $c_unc = Digest::MD5->new;
+ open(M, "$modname.obj") || die "Failed to open $modname.obj: $!";
+ $c_unc->addfile(*M);
+ close M;
+
+ system("$prog_gzip -9f $modname.obj && mv $modname.obj.gz $modname.obj")
+ if $compress;
+
+ my $c_compr = Digest::MD5->new;
+ open(M, "$modname.obj") || die "Failed to open $modname.obj: $!";
+ $c_compr->addfile(*M);
+ close M;
+
+ my $size = -s "$modname.obj";
+ my $md5_compr = $c_compr->hexdigest;
+ my $md5_uncompr = $c_unc->hexdigest;
+
+ my $section_attr = ($arch ne 'sparc' && $arch ne 'arm'
+ ? #'"a", @progbits' # Not Xen
+ '\"awx\", @progbits' # Xen
+ : '#alloc' );
+
+ write_to_file("$modname.extra.c",qq|
+ #include "mod_info.h"
+
+ extern char const _binary_${modname}_start[];
+
+ struct Mod_info const _binary_${modname}_info
+ __attribute__((section(".module_info"), aligned(4))) =
+ {
+ _binary_${modname}_start, $size, $uncompressed_size,
+ "$_file", "$cmdline",
+ "$md5_compr", "$md5_uncompr"
+ };
+
+ asm (".section .module_data, $section_attr \\n"
+ ".p2align 12 \\n"
+ ".global _binary_${modname}_start \\n"
+ "_binary_${modname}_start: \\n"
+ ".incbin \\"$modname.obj\\" \\n"
+ "_binary_${modname}_end: \\n");
+ |);
+
+ system("$prog_cc $flags_cc -c -o $modname.bin $modname.extra.c");
+ die "Assembling $modname failed" if $?;
+ unlink("$modname.extra.c", "$modname.obj", "$modname.ugz");
+}
+
+sub build_mbi_modules_obj($@)
+{
+ my $cmdline = shift;
+ my @mods = @_;
+ my $asm_string;
+
+ # generate mbi module structures
+ write_to_file("mbi_modules.c", qq|char const _mbi_cmdline[] = "$cmdline";|);
+ system("$prog_cc $flags_cc -c -o mbi_modules.bin mbi_modules.c");
+ die "Compiling mbi_modules.bin failed" if $?;
+ unlink("mbi_modules.c");
+
+}
+
+sub build_objects(@)
+{
+ my %entry = @_;
+ my @mods = @{$entry{mods}};
+ my $objs = "$output_dir/mbi_modules.bin";
+
+ unlink($make_inc_file);
+
+ # generate module-names
+ for (my $i = 0; $i < @mods; $i++) {
+ $mods[$i]->{modname} = sprintf "mod%02d", $i;
+ }
+
+ build_mbi_modules_obj($entry{bootstrap}{cmdline}, @mods);
+
+ for (my $i = 0; $i < @mods; $i++) {
+ build_obj($mods[$i]->{cmdline}, $mods[$i]->{modname},
+ $mods[$i]->{type} =~ /.+-nostrip$/);
+ $objs .= " $output_dir/$mods[$i]->{modname}.bin";
+ }
+
+ my $make_inc_str = "MODULE_OBJECT_FILES += $objs\n";
+ $make_inc_str .= "MOD_ADDR := $entry{modaddr}"
+ if defined $entry{modaddr};
+
+ write_to_file($make_inc_file, $make_inc_str);
+}
+
+
+sub list_files(@)
+{
+ my %entry = @_;
+ print join(' ', map { L4::ModList::search_file_or_die(first_word($_->{cmdline}),
+ $module_path) }
+ @{$entry{mods}}), "\n";
+}
+
+sub dump_entry(@)
+{
+ my %entry = @_;
+ print "modaddr=$entry{modaddr}\n" if defined $entry{modaddr};
+ print "$entry{bootstrap}{command}\n";
+ print "$entry{bootstrap}{cmdline}\n";
+ print join("\n", map { $_->{cmdline} } @{$entry{mods}}), "\n";
+ print join(' ', map { $_ } @{$entry{files}}), "\n";
+}
+
+# ------------------------------------------------------------------------
+
+if (!$ARGV[2]) {
+ print STDERR "Error: Invalid usage!\n";
+ usage();
+ exit 1;
+}
+
+if (defined $output_dir)
+ {
+ if (not -d $output_dir)
+ {
+ mkdir $output_dir || die "Cannot create '$output_dir': $!";
+ }
+ chdir $output_dir || die "Cannot change to directory '$output_dir': $!";
+ }
+
+my %entry = L4::ModList::get_module_entry($modulesfile, $entryname);
+
+if ($ARGV[0] eq 'build')
+ {
+ build_objects(%entry);
+ }
+elsif ($ARGV[0] eq 'list')
+ {
+ list_files(%entry);
+ }
+elsif ($ARGV[0] eq 'dump')
+ {
+ dump_entry(%entry);
+ }
--- /dev/null
+/**
+ * \file bootstrap/server/src/exec.c
+ * \brief ELF loader
+ *
+ * \date 2004
+ * \author Frank Mehnert <fm3@os.inf.tu-dresden.de>,
+ * Torsten Frenzel <frenzel@os.inf.tu-dresden.de> */
+
+/*
+ * (c) 2005-2009 Author(s)
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <alloca.h>
+
+#include <l4/util/elf.h>
+
+#include "exec.h"
+
+int
+exec_load_elf(exec_handler_func_t *handler,
+ void *handle, const char **error_msg, l4_addr_t *entry)
+{
+ exec_task_t *t = handle;
+ ElfW(Ehdr) *x = t->mod_start;
+ ElfW(Phdr) *phdr, *ph;
+ int i;
+
+ /* Read the ELF header. */
+
+ if (!l4util_elf_check_magic(x))
+ return *error_msg="no ELF executable", -1;
+
+ /* Make sure the file is of the right architecture. */
+ if (!l4util_elf_check_arch(x))
+ return *error_msg="wrong ELF architecture", -1;
+
+ *entry = (l4_addr_t) x->e_entry;
+
+ phdr = l4util_elf_phdr(x);
+
+ for (i = 0; i < x->e_phnum; i++)
+ {
+ ph = (ElfW(Phdr)*)((l4_addr_t)phdr + i * x->e_phentsize);
+ if (ph->p_type == PT_LOAD)
+ {
+ exec_sectype_t type = EXEC_SECTYPE_ALLOC |
+ EXEC_SECTYPE_LOAD;
+ if (ph->p_flags & PF_R) type |= EXEC_SECTYPE_READ;
+ if (ph->p_flags & PF_W) type |= EXEC_SECTYPE_WRITE;
+ if (ph->p_flags & PF_X) type |= EXEC_SECTYPE_EXECUTE;
+ (*handler)(handle,
+ ph->p_offset, ph->p_filesz,
+ ph->p_paddr, ph->p_vaddr, ph->p_memsz, type);
+ }
+ }
+
+ return *error_msg="", 0;
+}
--- /dev/null
+/*
+ * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ * Alexander Warg <warg@os.inf.tu-dresden.de>,
+ * Frank Mehnert <fm3@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#ifndef EXEC_H
+#define EXEC_H
+
+#include "types.h"
+#include <l4/sys/compiler.h>
+#include <l4/util/mb_info.h>
+
+typedef int exec_sectype_t;
+
+#define EXEC_SECTYPE_READ ((exec_sectype_t)0x000001)
+#define EXEC_SECTYPE_WRITE ((exec_sectype_t)0x000002)
+#define EXEC_SECTYPE_EXECUTE ((exec_sectype_t)0x000004)
+#define EXEC_SECTYPE_ALLOC ((exec_sectype_t)0x000100)
+#define EXEC_SECTYPE_LOAD ((exec_sectype_t)0x000200)
+
+
+typedef struct
+{
+ void *mod_start;
+ l4util_mb_mod_t *mod;
+ unsigned type;
+ l4_addr_t begin; /* program begin */
+ l4_addr_t end; /* program end */
+} exec_task_t;
+
+
+typedef int exec_handler_func_t(void *handle,
+ l4_addr_t file_ofs, l4_size_t file_size,
+ l4_addr_t mem_addr, l4_addr_t v_addr,
+ l4_size_t mem_size,
+ exec_sectype_t section_type);
+
+EXTERN_C_BEGIN
+
+int exec_load_elf(exec_handler_func_t *handler_exec,
+ void *handle, const char **error_msg, l4_addr_t *entry);
+
+EXTERN_C_END
+
+#endif
--- /dev/null
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Most of this file was originally the source file "inflate.c", written
+ * by Mark Adler. It has been very heavily modified. In particular, the
+ * original would run through the whole file at once, and this version can
+ * be stopped and restarted on any boundary during the decompression process.
+ *
+ * The license and header comments that file are included here.
+ */
+
+/* inflate.c -- Not copyrighted 1992 by Mark Adler
+ version c10p1, 10 January 1993 */
+
+/* You can do whatever you like with this source file, though I would
+ prefer that if you modify it and redistribute it that you include
+ comments to that effect with your name and the date. Thank you.
+ */
+
+/*
+ Inflate deflated (PKZIP's method 8 compressed) data. The compression
+ method searches for as much of the current string of bytes (up to a
+ length of 258) in the previous 32K bytes. If it doesn't find any
+ matches (of at least length 3), it codes the next byte. Otherwise, it
+ codes the length of the matched string and its distance backwards from
+ the current position. There is a single Huffman code that codes both
+ single bytes (called "literals") and match lengths. A second Huffman
+ code codes the distance information, which follows a length code. Each
+ length or distance code actually represents a base value and a number
+ of "extra" (sometimes zero) bits to get to add to the base value. At
+ the end of each deflated block is a special end-of-block (EOB) literal/
+ length code. The decoding process is basically: get a literal/length
+ code; if EOB then done; if a literal, emit the decoded byte; if a
+ length then get the distance and emit the referred-to bytes from the
+ sliding window of previously emitted data.
+
+ There are (currently) three kinds of inflate blocks: stored, fixed, and
+ dynamic. The compressor deals with some chunk of data at a time, and
+ decides which method to use on a chunk-by-chunk basis. A chunk might
+ typically be 32K or 64K. If the chunk is uncompressible, then the
+ "stored" method is used. In this case, the bytes are simply stored as
+ is, eight bits per byte, with none of the above coding. The bytes are
+ preceded by a count, since there is no longer an EOB code.
+
+ If the data is compressible, then either the fixed or dynamic methods
+ are used. In the dynamic method, the compressed data is preceded by
+ an encoding of the literal/length and distance Huffman codes that are
+ to be used to decode this block. The representation is itself Huffman
+ coded, and so is preceded by a description of that code. These code
+ descriptions take up a little space, and so for small blocks, there is
+ a predefined set of codes, called the fixed codes. The fixed method is
+ used if the block codes up smaller that way (usually for quite small
+ chunks), otherwise the dynamic method is used. In the latter case, the
+ codes are customized to the probabilities in the current block, and so
+ can code it much better than the pre-determined fixed codes.
+
+ The Huffman codes themselves are decoded using a mutli-level table
+ lookup, in order to maximize the speed of decoding plus the speed of
+ building the decoding tables. See the comments below that precede the
+ lbits and dbits tuning parameters.
+ */
+
+
+/*
+ Notes beyond the 1.93a appnote.txt:
+
+ 1. Distance pointers never point before the beginning of the output
+ stream.
+ 2. Distance pointers can point back across blocks, up to 32k away.
+ 3. There is an implied maximum of 7 bits for the bit length table and
+ 15 bits for the actual data.
+ 4. If only one code exists, then it is encoded using one bit. (Zero
+ would be more efficient, but perhaps a little confusing.) If two
+ codes exist, they are coded using one bit each (0 and 1).
+ 5. There is no way of sending zero distance codes--a dummy must be
+ sent if there are none. (History: a pre 2.0 version of PKZIP would
+ store blocks with no distance codes, but this was discovered to be
+ too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
+ zero distance codes, which is sent as one code of zero bits in
+ length.
+ 6. There are up to 286 literal/length codes. Code 256 represents the
+ end-of-block. Note however that the static length tree defines
+ 288 codes just to fill out the Huffman codes. Codes 286 and 287
+ cannot be used though, since there is no length base or extra bits
+ defined for them. Similarly, there are up to 30 distance codes.
+ However, static trees define 32 codes (all 5 bits) to fill out the
+ Huffman codes, but the last two had better not show up in the data.
+ 7. Unzip can check dynamic Huffman blocks for complete code sets.
+ The exception is that a single code would not be complete (see #4).
+ 8. The five bits following the block type is really the number of
+ literal codes sent minus 257.
+ 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+ (1+6+6). Therefore, to output three times the length, you output
+ three codes (1+1+1), whereas to output four times the same length,
+ you only need two codes (1+3). Hmm.
+ 10. In the tree reconstruction algorithm, Code = Code + Increment
+ only if BitLength(i) is not zero. (Pretty obvious.)
+ 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
+ 12. Note: length code 284 can represent 227-258, but length code 285
+ really is 258. The last length deserves its own, short code
+ since it gets used a lot in very redundant files. The length
+ 258 is special since 258 - 3 (the min match length) is 255.
+ 13. The literal/length and distance code bit lengths are read as a
+ single stream of lengths. It is possible (and advantageous) for
+ a repeat code (16, 17, or 18) to go across the boundary between
+ the two sets of lengths.
+ */
+
+#ifndef NO_DECOMPRESSION
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "gunzip.h"
+
+unsigned int filepos;
+unsigned int filemax;
+unsigned int fsmax; /* max size of fs/readable media */
+
+grub_error_t errnum;
+
+/* whether to show decompression progress or not */
+enum { do_show_progress = 1 };
+
+/* so we can disable decompression */
+int no_decompression = 0;
+
+/* used to tell if "read" should be redirected to "gunzip_read" */
+unsigned int compressed_file;
+
+/* internal variables only */
+static unsigned int gzip_data_offset;
+static int gzip_filepos;
+static int gzip_filemax;
+static int gzip_fsmax;
+static int saved_filepos;
+static unsigned long gzip_crc;
+
+/* internal extra variables for use of inflate code */
+static int block_type;
+static unsigned int block_len;
+static int last_block;
+static int code_state;
+
+
+/* Function prototypes */
+static void initialize_tables (void);
+
+static void show_progress(int done, int len)
+{
+ int r = printf("%lld%%", ((unsigned long long)done * 100) / len);
+ while (r-- > 0)
+ putchar('\b');
+ fflush(NULL);
+}
+
+/*
+ * Linear allocator.
+ */
+
+static unsigned long linalloc_topaddr;
+
+static void *
+linalloc (int size)
+{
+ extern void *lin_alloc_buffer;
+ unsigned long newaddr = (linalloc_topaddr - size) & ~3;
+ if (newaddr < (unsigned long)lin_alloc_buffer)
+ panic("Out of memory while uncompressing");
+ linalloc_topaddr = newaddr;
+ return (void *) linalloc_topaddr;
+}
+
+static void
+reset_linalloc (void)
+{
+ linalloc_topaddr = RAW_ADDR (UPPER_MEM_LINALLOC);
+}
+
+
+/* internal variable swap function */
+static void
+gunzip_swap_values (void)
+{
+ register int itmp;
+
+ /* swap filepos */
+ itmp = filepos;
+ filepos = gzip_filepos;
+ gzip_filepos = itmp;
+
+ /* swap filemax */
+ itmp = filemax;
+ filemax = gzip_filemax;
+ gzip_filemax = itmp;
+
+ /* swap fsmax */
+ itmp = fsmax;
+ fsmax = gzip_fsmax;
+ gzip_fsmax = itmp;
+}
+
+
+/* internal function for eating variable-length header fields */
+static int
+bad_field (int len)
+{
+ unsigned char ch = 1;
+ int not_retval = 1;
+
+ do
+ {
+ if (len >= 0)
+ {
+ if (!(len--))
+ break;
+ }
+ else
+ {
+ if (!ch)
+ break;
+ }
+ }
+ while ((not_retval = grub_read (&ch, 1)) == 1);
+
+ return (!not_retval);
+}
+
+
+/* Little-Endian defines for the 2-byte magic number for gzip files */
+#define GZIP_HDR_LE 0x8B1F
+#define OLD_GZIP_HDR_LE 0x9E1F
+
+/* Compression methods (see algorithm.doc) */
+#define STORED 0
+#define COMPRESSED 1
+#define PACKED 2
+#define LZHED 3
+/* methods 4 to 7 reserved */
+#define DEFLATED 8
+#define MAX_METHODS 9
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
+#define RESERVED 0xC0 /* bit 6,7: reserved */
+
+#define UNSUPP_FLAGS (CONTINUATION|ENCRYPTED|RESERVED)
+
+/* inflate block codes */
+#define INFLATE_STORED 0
+#define INFLATE_FIXED 1
+#define INFLATE_DYNAMIC 2
+
+typedef unsigned char uch;
+typedef unsigned short ush;
+typedef unsigned long ulg;
+
+/*
+ * Window Size
+ *
+ * This must be a power of two, and at least 32K for zip's deflate method
+ */
+
+#define WSIZE 0x8000
+
+
+int
+gunzip_test_header (void)
+{
+ unsigned char buf[10] __attribute__((aligned(4)));
+
+ /* "compressed_file" is already reset to zero by this point */
+
+ /*
+ * This checks if the file is gzipped. If a problem occurs here
+ * (other than a real error with the disk) then we don't think it
+ * is a compressed file, and simply mark it as such.
+ */
+ if (no_decompression
+ || grub_read (buf, 10) != 10
+ || ((*((unsigned short *) buf) != GZIP_HDR_LE)
+ && (*((unsigned short *) buf) != OLD_GZIP_HDR_LE)))
+ {
+ filepos = 0;
+ return ! errnum;
+ }
+
+ /*
+ * This does consistency checking on the header data. If a
+ * problem occurs from here on, then we have corrupt or otherwise
+ * bad data, and the error should be reported to the user.
+ */
+ if (buf[2] != DEFLATED
+ || (buf[3] & UNSUPP_FLAGS)
+ || ((buf[3] & EXTRA_FIELD)
+ && (grub_read (buf, 2) != 2
+ || bad_field (*((unsigned short *) buf))))
+ || ((buf[3] & ORIG_NAME) && bad_field (-1))
+ || ((buf[3] & COMMENT) && bad_field (-1)))
+ {
+ if (! errnum)
+ errnum = ERR_BAD_GZIP_HEADER;
+
+ return 0;
+ }
+
+ gzip_data_offset = filepos;
+
+ filepos = filemax - 8;
+
+ if (grub_read (buf, 8) != 8)
+ {
+ if (! errnum)
+ errnum = ERR_BAD_GZIP_HEADER;
+
+ return 0;
+ }
+
+ gzip_crc = *((unsigned long *) buf);
+ gzip_fsmax = gzip_filemax = *((unsigned long *) (buf + 4));
+
+ initialize_tables ();
+
+ compressed_file = 1;
+ gunzip_swap_values ();
+ /*
+ * Now "gzip_*" values refer to the compressed data.
+ */
+
+ filepos = 0;
+
+ return 1;
+}
+
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+ that have 16-bit pointers (e.g. PC's in the small or medium model).
+ Valid extra bits are 0..13. e == 15 is EOB (end of block), e == 16
+ means that v is a literal, 16 < e < 32 means that v is a pointer to
+ the next table, which codes e - 16 bits, and lastly e == 99 indicates
+ an unused code. If a code with e == 99 is looked up, this implies an
+ error in the data. */
+struct huft
+{
+ uch e; /* number of extra bits or operation */
+ uch b; /* number of bits in this code or subcode */
+ union
+ {
+ ush n; /* literal, length base, or distance base */
+ struct huft *t; /* pointer to next level of table */
+ }
+ v;
+};
+
+
+/* The inflate algorithm uses a sliding 32K byte window on the uncompressed
+ stream to find repeated byte strings. This is implemented here as a
+ circular buffer. The index is updated simply by incrementing and then
+ and'ing with 0x7fff (32K-1). */
+/* It is left to other modules to supply the 32K area. It is assumed
+ to be usable as if it were declared "uch slide[32768];" or as just
+ "uch *slide;" and then malloc'ed in the latter case. The definition
+ must be in unzip.h, included above. */
+
+
+/* sliding window in uncompressed data */
+static uch slide[WSIZE];
+
+/* current position in slide */
+static unsigned wp;
+
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+static unsigned bitorder[] =
+{ /* Order of the bit length code lengths */
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+static ush cplens[] __attribute__((aligned(4))) =
+{ /* Copy lengths for literal codes 257..285 */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ /* note: see note #13 above about the 258 in this list. */
+static ush cplext[] __attribute__((aligned(4))) =
+{ /* Extra bits for literal codes 257..285 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */
+static ush cpdist[] __attribute__((aligned(4))) =
+{ /* Copy offsets for distance codes 0..29 */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577};
+static ush cpdext[] __attribute__((aligned(4))) =
+{ /* Extra bits for distance codes */
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13};
+
+
+/*
+ Huffman code decoding is performed using a multi-level table lookup.
+ The fastest way to decode is to simply build a lookup table whose
+ size is determined by the longest code. However, the time it takes
+ to build this table can also be a factor if the data being decoded
+ is not very long. The most common codes are necessarily the
+ shortest codes, so those codes dominate the decoding time, and hence
+ the speed. The idea is you can have a shorter table that decodes the
+ shorter, more probable codes, and then point to subsidiary tables for
+ the longer codes. The time it costs to decode the longer codes is
+ then traded against the time it takes to make longer tables.
+
+ This results of this trade are in the variables lbits and dbits
+ below. lbits is the number of bits the first level table for literal/
+ length codes can decode in one step, and dbits is the same thing for
+ the distance codes. Subsequent tables are also less than or equal to
+ those sizes. These values may be adjusted either when all of the
+ codes are shorter than that, in which case the longest code length in
+ bits is used, or when the shortest code is *longer* than the requested
+ table size, in which case the length of the shortest code in bits is
+ used.
+
+ There are two different values for the two tables, since they code a
+ different number of possibilities each. The literal/length table
+ codes 286 possible values, or in a flat code, a little over eight
+ bits. The distance table codes 30 possible values, or a little less
+ than five bits, flat. The optimum values for speed end up being
+ about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+ The optimum values may differ though from machine to machine, and
+ possibly even between compilers. Your mileage may vary.
+ */
+
+
+static int lbits = 9; /* bits in base literal/length lookup table */
+static int dbits = 6; /* bits in base distance lookup table */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
+#define BMAX 16 /* maximum bit length of any code (16 for explode) */
+#define N_MAX 288 /* maximum number of codes in any set */
+
+
+static unsigned hufts; /* track memory usage */
+
+
+/* Macros for inflate() bit peeking and grabbing.
+ The usage is:
+
+ NEEDBITS(j)
+ x = b & mask_bits[j];
+ DUMPBITS(j)
+
+ where NEEDBITS makes sure that b has at least j bits in it, and
+ DUMPBITS removes the bits from b. The macros use the variable k
+ for the number of bits in b. Normally, b and k are register
+ variables for speed, and are initialized at the beginning of a
+ routine that uses these macros from a global bit buffer and count.
+
+ If we assume that EOB will be the longest code, then we will never
+ ask for bits with NEEDBITS that are beyond the end of the stream.
+ So, NEEDBITS should not read any more bytes than are needed to
+ meet the request. Then no bytes need to be "returned" to the buffer
+ at the end of the last block.
+
+ However, this assumption is not true for fixed blocks--the EOB code
+ is 7 bits, but the other literal/length codes can be 8 or 9 bits.
+ (The EOB code is shorter than other codes because fixed blocks are
+ generally short. So, while a block always has an EOB, many other
+ literal/length codes have a significantly lower probability of
+ showing up at all.) However, by making the first table have a
+ lookup of seven bits, the EOB code will be found in that first
+ lookup, and so will not require that too many bits be pulled from
+ the stream.
+ */
+
+static ulg bb; /* bit buffer */
+static unsigned bk; /* bits in bit buffer */
+
+static ush mask_bits[] =
+{
+ 0x0000,
+ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+#define NEEDBITS(n) do {while(k<(n)){b|=((ulg)get_byte())<<k;k+=8;}} while (0)
+#define DUMPBITS(n) do {b>>=(n);k-=(n);} while (0)
+
+#define INBUFSIZ 0x2000
+
+static unsigned char inbuf[INBUFSIZ];
+static int bufloc;
+
+static int
+get_byte (void)
+{
+ if (filepos == gzip_data_offset || bufloc == INBUFSIZ)
+ {
+ bufloc = 0;
+ grub_read (inbuf, INBUFSIZ);
+ }
+
+ return inbuf[bufloc++];
+}
+
+/* decompression global pointers */
+static struct huft *tl; /* literal/length code table */
+static struct huft *td; /* distance code table */
+static int bl; /* lookup bits for tl */
+static int bd; /* lookup bits for td */
+
+
+/* more function prototypes */
+static int huft_build (unsigned *, unsigned, unsigned, ush *, ush *,
+ struct huft **, int *);
+static int inflate_codes_in_window (void);
+
+
+/* Given a list of code lengths and a maximum table size, make a set of
+ tables to decode that set of codes. Return zero on success, one if
+ the given code set is incomplete (the tables are still built in this
+ case), two if the input is invalid (all zero length codes or an
+ oversubscribed set of lengths), and three if not enough memory. */
+
+static int
+huft_build (unsigned *b, /* code lengths in bits (all assumed <= BMAX) */
+ unsigned n, /* number of codes (assumed <= N_MAX) */
+ unsigned s, /* number of simple-valued codes (0..s-1) */
+ ush * d, /* list of base values for non-simple codes */
+ ush * e, /* list of extra bits for non-simple codes */
+ struct huft **t, /* result: starting table */
+ int *m) /* maximum lookup bits, returns actual */
+{
+ unsigned a; /* counter for codes of length k */
+ unsigned c[BMAX + 1]; /* bit length count table */
+ unsigned f; /* i repeats in table every f entries */
+ int g; /* maximum code length */
+ int h; /* table level */
+ register unsigned i; /* counter, current code */
+ register unsigned j; /* counter */
+ register int k; /* number of bits in current code */
+ int l; /* bits per table (returned in m) */
+ register unsigned *p; /* pointer into c[], b[], or v[] */
+ register struct huft *q; /* points to current table */
+ struct huft r; /* table entry for structure assignment */
+ struct huft *u[BMAX]; /* table stack */
+ unsigned v[N_MAX]; /* values in order of bit length */
+ register int w; /* bits before this table == (l * h) */
+ unsigned x[BMAX + 1]; /* bit offsets, then code stack */
+ unsigned *xp; /* pointer into x */
+ int y; /* number of dummy codes added */
+ unsigned z; /* number of entries in current table */
+
+ /* Generate counts for each bit length */
+ memset ((char *) c, 0, sizeof (c));
+ p = b;
+ i = n;
+ do
+ {
+ c[*p]++; /* assume all entries <= BMAX */
+ p++; /* Can't combine with above line (Solaris bug) */
+ }
+ while (--i);
+ if (c[0] == n) /* null input--all zero length codes */
+ {
+ *t = (struct huft *) NULL;
+ *m = 0;
+ return 0;
+ }
+
+ /* Find minimum and maximum length, bound *m by those */
+ l = *m;
+ for (j = 1; j <= BMAX; j++)
+ if (c[j])
+ break;
+ k = j; /* minimum code length */
+ if ((unsigned) l < j)
+ l = j;
+ for (i = BMAX; i; i--)
+ if (c[i])
+ break;
+ g = i; /* maximum code length */
+ if ((unsigned) l > i)
+ l = i;
+ *m = l;
+
+ /* Adjust last length count to fill out codes, if needed */
+ for (y = 1 << j; j < i; j++, y <<= 1)
+ if ((y -= c[j]) < 0)
+ return 2; /* bad input: more codes than bits */
+ if ((y -= c[i]) < 0)
+ return 2;
+ c[i] += y;
+
+ /* Generate starting offsets into the value table for each length */
+ x[1] = j = 0;
+ p = c + 1;
+ xp = x + 2;
+ while (--i)
+ { /* note that i == g from above */
+ *xp++ = (j += *p++);
+ }
+
+ /* Make a table of values in order of bit lengths */
+ p = b;
+ i = 0;
+ do
+ {
+ if ((j = *p++) != 0)
+ v[x[j]++] = i;
+ }
+ while (++i < n);
+
+ /* Generate the Huffman codes and for each, make the table entries */
+ x[0] = i = 0; /* first Huffman code is zero */
+ p = v; /* grab values in bit order */
+ h = -1; /* no tables yet--level -1 */
+ w = -l; /* bits decoded == (l * h) */
+ u[0] = (struct huft *) NULL; /* just to keep compilers happy */
+ q = (struct huft *) NULL; /* ditto */
+ z = 0; /* ditto */
+
+ /* go through the bit lengths (k already is bits in shortest code) */
+ for (; k <= g; k++)
+ {
+ a = c[k];
+ while (a--)
+ {
+ /* here i is the Huffman code of length k bits for value *p */
+ /* make tables up to required level */
+ while (k > w + l)
+ {
+ h++;
+ w += l; /* previous table always l bits */
+
+ /* compute minimum size table less than or equal to l bits */
+ z = (z = g - w) > (unsigned) l ? l : z; /* upper limit on table size */
+ if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
+ { /* too few codes for k-w bit table */
+ f -= a + 1; /* deduct codes from patterns left */
+ xp = c + k;
+ while (++j < z) /* try smaller tables up to z bits */
+ {
+ if ((f <<= 1) <= *++xp)
+ break; /* enough codes to use up j bits */
+ f -= *xp; /* else deduct codes from patterns */
+ }
+ }
+ z = 1 << j; /* table entries for j-bit table */
+
+ /* allocate and link in new table */
+ q = (struct huft *) linalloc ((z + 1) * sizeof (struct huft));
+
+ hufts += z + 1; /* track memory usage */
+ *t = q + 1; /* link to list for huft_free() */
+ *(t = &(q->v.t)) = (struct huft *) NULL;
+ u[h] = ++q; /* table starts after link */
+
+ /* connect to last table, if there is one */
+ if (h)
+ {
+ x[h] = i; /* save pattern for backing up */
+ r.b = (uch) l; /* bits to dump before this table */
+ r.e = (uch) (16 + j); /* bits in this table */
+ r.v.t = q; /* pointer to this table */
+ j = i >> (w - l); /* (get around Turbo C bug) */
+ u[h - 1][j] = r; /* connect to last table */
+ }
+ }
+
+ /* set up table entry in r */
+ r.b = (uch) (k - w);
+ if (p >= v + n)
+ r.e = 99; /* out of values--invalid code */
+ else if (*p < s)
+ {
+ r.e = (uch) (*p < 256 ? 16 : 15); /* 256 is end-of-block code */
+ r.v.n = (ush) (*p); /* simple code is just the value */
+ p++; /* one compiler does not like *p++ */
+ }
+ else
+ {
+ r.e = (uch) e[*p - s]; /* non-simple--look up in lists */
+ r.v.n = d[*p++ - s];
+ }
+
+ /* fill code-like entries with r */
+ f = 1 << (k - w);
+ for (j = i >> w; j < z; j += f)
+ q[j] = r;
+
+ /* backwards increment the k-bit code i */
+ for (j = 1 << (k - 1); i & j; j >>= 1)
+ i ^= j;
+ i ^= j;
+
+ /* backup over finished tables */
+ while ((i & ((1 << w) - 1)) != x[h])
+ {
+ h--; /* don't need to update q */
+ w -= l;
+ }
+ }
+ }
+
+ /* Return true (1) if we were given an incomplete table */
+ return y != 0 && g != 1;
+}
+
+
+/*
+ * inflate (decompress) the codes in a deflated (compressed) block.
+ * Return an error code or zero if it all goes ok.
+ */
+
+static unsigned inflate_n, inflate_d;
+
+static int
+inflate_codes_in_window (void)
+{
+ register unsigned e; /* table entry flag/number of extra bits */
+ unsigned n, d; /* length and index for copy */
+ unsigned w; /* current window position */
+ struct huft *t; /* pointer to table entry */
+ unsigned ml, md; /* masks for bl and bd bits */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+ /* make local copies of globals */
+ d = inflate_d;
+ n = inflate_n;
+ b = bb; /* initialize bit buffer */
+ k = bk;
+ w = wp; /* initialize window position */
+
+ /* inflate the coded data */
+ ml = mask_bits[bl]; /* precompute masks for speed */
+ md = mask_bits[bd];
+ for (;;) /* do until end of block */
+ {
+ if (!code_state)
+ {
+ NEEDBITS ((unsigned) bl);
+ if ((e = (t = tl + ((unsigned) b & ml))->e) > 16)
+ do
+ {
+ if (e == 99)
+ {
+ errnum = ERR_BAD_GZIP_DATA;
+ return 0;
+ }
+ DUMPBITS (t->b);
+ e -= 16;
+ NEEDBITS (e);
+ }
+ while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16);
+ DUMPBITS (t->b);
+
+ if (e == 16) /* then it's a literal */
+ {
+ slide[w++] = (uch) t->v.n;
+ if (w == WSIZE)
+ break;
+ }
+ else
+ /* it's an EOB or a length */
+ {
+ /* exit if end of block */
+ if (e == 15)
+ {
+ block_len = 0;
+ break;
+ }
+
+ /* get length of block to copy */
+ NEEDBITS (e);
+ n = t->v.n + ((unsigned) b & mask_bits[e]);
+ DUMPBITS (e);
+
+ /* decode distance of block to copy */
+ NEEDBITS ((unsigned) bd);
+ if ((e = (t = td + ((unsigned) b & md))->e) > 16)
+ do
+ {
+ if (e == 99)
+ {
+ errnum = ERR_BAD_GZIP_DATA;
+ return 0;
+ }
+ DUMPBITS (t->b);
+ e -= 16;
+ NEEDBITS (e);
+ }
+ while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e)
+ > 16);
+ DUMPBITS (t->b);
+ NEEDBITS (e);
+ d = w - t->v.n - ((unsigned) b & mask_bits[e]);
+ DUMPBITS (e);
+ code_state++;
+ }
+ }
+
+ if (code_state)
+ {
+ /* do the copy */
+ do
+ {
+ n -= (e = (e = WSIZE - ((d &= WSIZE - 1) > w ? d : w)) > n ? n
+ : e);
+ if (w - d >= e)
+ {
+ memmove (slide + w, slide + d, e);
+ w += e;
+ d += e;
+ }
+ else
+ /* purposefully use the overlap for extra copies here!! */
+ {
+ while (e--)
+ slide[w++] = slide[d++];
+ }
+ if (w == WSIZE)
+ break;
+ }
+ while (n);
+
+ if (!n)
+ code_state--;
+
+ /* did we break from the loop too soon? */
+ if (w == WSIZE)
+ break;
+ }
+ }
+
+ /* restore the globals from the locals */
+ inflate_d = d;
+ inflate_n = n;
+ wp = w; /* restore global window pointer */
+ bb = b; /* restore global bit buffer */
+ bk = k;
+
+ return !block_len;
+}
+
+
+/* get header for an inflated type 0 (stored) block. */
+
+static void
+init_stored_block (void)
+{
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+ /* make local copies of globals */
+ b = bb; /* initialize bit buffer */
+ k = bk;
+
+ /* go to byte boundary */
+ DUMPBITS (k & 7);
+
+ /* get the length and its complement */
+ NEEDBITS (16);
+ block_len = ((unsigned) b & 0xffff);
+ DUMPBITS (16);
+ NEEDBITS (16);
+ if (block_len != (unsigned) ((~b) & 0xffff))
+ errnum = ERR_BAD_GZIP_DATA;
+ DUMPBITS (16);
+
+ /* restore global variables */
+ bb = b;
+ bk = k;
+}
+
+
+/* get header for an inflated type 1 (fixed Huffman codes) block. We should
+ either replace this with a custom decoder, or at least precompute the
+ Huffman tables. */
+
+static void
+init_fixed_block (void)
+{
+ int i; /* temporary variable */
+ unsigned l[288]; /* length list for huft_build */
+
+ /* set up literal table */
+ for (i = 0; i < 144; i++)
+ l[i] = 8;
+ for (; i < 256; i++)
+ l[i] = 9;
+ for (; i < 280; i++)
+ l[i] = 7;
+ for (; i < 288; i++) /* make a complete, but wrong code set */
+ l[i] = 8;
+ bl = 7;
+ if ((i = huft_build (l, 288, 257, cplens, cplext, &tl, &bl)) != 0)
+ {
+ errnum = ERR_BAD_GZIP_DATA;
+ return;
+ }
+
+ /* set up distance table */
+ for (i = 0; i < 30; i++) /* make an incomplete code set */
+ l[i] = 5;
+ bd = 5;
+ if ((i = huft_build (l, 30, 0, cpdist, cpdext, &td, &bd)) > 1)
+ {
+ errnum = ERR_BAD_GZIP_DATA;
+ return;
+ }
+
+ /* indicate we're now working on a block */
+ code_state = 0;
+ block_len++;
+}
+
+
+/* get header for an inflated type 2 (dynamic Huffman codes) block. */
+
+static void
+init_dynamic_block (void)
+{
+ int i; /* temporary variables */
+ unsigned j;
+ unsigned l; /* last length */
+ unsigned m; /* mask for bit lengths table */
+ unsigned n; /* number of lengths to get */
+ unsigned nb; /* number of bit length codes */
+ unsigned nl; /* number of literal/length codes */
+ unsigned nd; /* number of distance codes */
+ unsigned ll[286 + 30]; /* literal/length and distance code lengths */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+ /* make local bit buffer */
+ b = bb;
+ k = bk;
+
+ /* read in table lengths */
+ NEEDBITS (5);
+ nl = 257 + ((unsigned) b & 0x1f); /* number of literal/length codes */
+ DUMPBITS (5);
+ NEEDBITS (5);
+ nd = 1 + ((unsigned) b & 0x1f); /* number of distance codes */
+ DUMPBITS (5);
+ NEEDBITS (4);
+ nb = 4 + ((unsigned) b & 0xf); /* number of bit length codes */
+ DUMPBITS (4);
+ if (nl > 286 || nd > 30)
+ {
+ errnum = ERR_BAD_GZIP_DATA;
+ return;
+ }
+
+ /* read in bit-length-code lengths */
+ for (j = 0; j < nb; j++)
+ {
+ NEEDBITS (3);
+ ll[bitorder[j]] = (unsigned) b & 7;
+ DUMPBITS (3);
+ }
+ for (; j < 19; j++)
+ ll[bitorder[j]] = 0;
+
+ /* build decoding table for trees--single level, 7 bit lookup */
+ bl = 7;
+ if ((i = huft_build (ll, 19, 19, NULL, NULL, &tl, &bl)) != 0)
+ {
+ errnum = ERR_BAD_GZIP_DATA;
+ return;
+ }
+
+ /* read in literal and distance code lengths */
+ n = nl + nd;
+ m = mask_bits[bl];
+ i = l = 0;
+ while ((unsigned) i < n)
+ {
+ NEEDBITS ((unsigned) bl);
+ j = (td = tl + ((unsigned) b & m))->b;
+ DUMPBITS (j);
+ j = td->v.n;
+ if (j < 16) /* length of code in bits (0..15) */
+ ll[i++] = l = j; /* save last length in l */
+ else if (j == 16) /* repeat last length 3 to 6 times */
+ {
+ NEEDBITS (2);
+ j = 3 + ((unsigned) b & 3);
+ DUMPBITS (2);
+ if ((unsigned) i + j > n)
+ {
+ errnum = ERR_BAD_GZIP_DATA;
+ return;
+ }
+ while (j--)
+ ll[i++] = l;
+ }
+ else if (j == 17) /* 3 to 10 zero length codes */
+ {
+ NEEDBITS (3);
+ j = 3 + ((unsigned) b & 7);
+ DUMPBITS (3);
+ if ((unsigned) i + j > n)
+ {
+ errnum = ERR_BAD_GZIP_DATA;
+ return;
+ }
+ while (j--)
+ ll[i++] = 0;
+ l = 0;
+ }
+ else
+ /* j == 18: 11 to 138 zero length codes */
+ {
+ NEEDBITS (7);
+ j = 11 + ((unsigned) b & 0x7f);
+ DUMPBITS (7);
+ if ((unsigned) i + j > n)
+ {
+ errnum = ERR_BAD_GZIP_DATA;
+ return;
+ }
+ while (j--)
+ ll[i++] = 0;
+ l = 0;
+ }
+ }
+
+ /* free decoding table for trees */
+ reset_linalloc ();
+
+ /* restore the global bit buffer */
+ bb = b;
+ bk = k;
+
+ /* build the decoding tables for literal/length and distance codes */
+ bl = lbits;
+ if ((i = huft_build (ll, nl, 257, cplens, cplext, &tl, &bl)) != 0)
+ {
+#if 0
+ if (i == 1)
+ printf ("gunzip: incomplete literal tree\n");
+#endif
+
+ errnum = ERR_BAD_GZIP_DATA;
+ return;
+ }
+ bd = dbits;
+ if ((i = huft_build (ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0)
+ {
+#if 0
+ if (i == 1)
+ printf ("gunzip: incomplete distance tree\n");
+#endif
+
+ errnum = ERR_BAD_GZIP_DATA;
+ return;
+ }
+
+ /* indicate we're now working on a block */
+ code_state = 0;
+ block_len++;
+}
+
+
+static void
+get_new_block (void)
+{
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+ hufts = 0;
+
+ /* make local bit buffer */
+ b = bb;
+ k = bk;
+
+ /* read in last block bit */
+ NEEDBITS (1);
+ last_block = (int) b & 1;
+ DUMPBITS (1);
+
+ /* read in block type */
+ NEEDBITS (2);
+ block_type = (unsigned) b & 3;
+ DUMPBITS (2);
+
+ /* restore the global bit buffer */
+ bb = b;
+ bk = k;
+
+ if (block_type == INFLATE_STORED)
+ init_stored_block ();
+ if (block_type == INFLATE_FIXED)
+ init_fixed_block ();
+ if (block_type == INFLATE_DYNAMIC)
+ init_dynamic_block ();
+}
+
+
+static void
+inflate_window (void)
+{
+ /* initialize window */
+ wp = 0;
+
+ /*
+ * Main decompression loop.
+ */
+
+ while (wp < WSIZE && !errnum)
+ {
+ if (!block_len)
+ {
+ if (last_block)
+ break;
+
+ get_new_block ();
+ }
+
+ if (block_type > INFLATE_DYNAMIC)
+ errnum = ERR_BAD_GZIP_DATA;
+
+ if (errnum)
+ return;
+
+ /*
+ * Expand stored block here.
+ */
+ if (block_type == INFLATE_STORED)
+ {
+ int w = wp;
+
+ /*
+ * This is basically a glorified pass-through
+ */
+
+ while (block_len && w < WSIZE && !errnum)
+ {
+ slide[w++] = get_byte ();
+ block_len--;
+ }
+
+ wp = w;
+
+ continue;
+ }
+
+ /*
+ * Expand other kind of block.
+ */
+
+ if (inflate_codes_in_window ())
+ reset_linalloc ();
+ }
+
+ saved_filepos += WSIZE;
+
+ /* XXX do CRC calculation here! */
+}
+
+
+static void
+initialize_tables (void)
+{
+ saved_filepos = 0;
+ filepos = gzip_data_offset;
+
+ /* initialize window, bit buffer */
+ bk = 0;
+ bb = 0;
+
+ /* reset partial decompression code */
+ last_block = 0;
+ block_len = 0;
+
+ /* reset memory allocation stuff */
+ reset_linalloc ();
+}
+
+
+int
+gunzip_read (unsigned char *buf, int len)
+{
+ int ret = 0;
+ int real_len = len;
+
+ compressed_file = 0;
+ gunzip_swap_values ();
+ /*
+ * Now "gzip_*" values refer to the uncompressed data.
+ */
+
+ /* do we reset decompression to the beginning of the file? */
+ if (saved_filepos > gzip_filepos + WSIZE)
+ initialize_tables ();
+
+ /*
+ * This loop operates upon uncompressed data only. The only
+ * special thing it does is to make sure the decompression
+ * window is within the range of data it needs.
+ */
+
+ while (len > 0 && !errnum)
+ {
+ register int size;
+ register char *srcaddr;
+
+ while (gzip_filepos >= saved_filepos)
+ inflate_window ();
+
+ srcaddr = (char *) ((gzip_filepos & (WSIZE - 1)) + slide);
+ size = saved_filepos - gzip_filepos;
+ if (size > len)
+ size = len;
+
+ memmove (buf, srcaddr, size);
+
+ buf += size;
+ len -= size;
+ gzip_filepos += size;
+ ret += size;
+
+ if (do_show_progress)
+ show_progress(ret, real_len);
+ }
+
+ compressed_file = 1;
+ gunzip_swap_values ();
+ /*
+ * Now "gzip_*" values refer to the compressed data.
+ */
+
+ if (errnum)
+ ret = 0;
+
+ return ret;
+}
+
+#endif /* ! NO_DECOMPRESSION */
--- /dev/null
+#ifndef __BOOTSTRAP__GUNZIP_H__
+#define __BOOTSTRAP__GUNZIP_H__
+
+#include <l4/sys/l4int.h>
+#include "panic.h"
+
+typedef enum
+{
+ ERR_NONE = 0,
+ ERR_BAD_GZIP_DATA,
+ ERR_BAD_GZIP_HEADER,
+
+} grub_error_t;
+
+l4_addr_t gunzip_upper_mem_linalloc(void);
+#define UPPER_MEM_LINALLOC gunzip_upper_mem_linalloc()
+
+#define RAW_ADDR(x) (x)
+#define RAW_SEG(x) (x)
+
+extern unsigned int filepos;
+extern unsigned int filemax;
+extern unsigned int fsmax; /* max size of fs/readable media */
+extern unsigned int compressed_file;
+extern grub_error_t errnum;
+
+/* Read LEN bytes into BUF from the file that was opened with
+ GRUB_OPEN. If LEN is -1, read all the remaining data in the file. */
+int grub_read (unsigned char *buf, int len);
+
+int gunzip_read (unsigned char *buf, int len);
+int gunzip_test_header (void);
+
+void *memmove(void *dest, const void *src, size_t n);
+
+#endif /* ! __BOOTSTRAP__GUNZIP_H__ */
--- /dev/null
+/*
+ * (c) 2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#ifndef INIT_KIP_ARCH_H__
+#define INIT_KIP_ARCH_H__
+
+#include <l4/sys/kip.h>
+
+#if defined(ARCH_ppc32)
+void init_kip_v2_arch(l4_kernel_info_t *);
+#endif
+
+#endif
+
--- /dev/null
+/*
+ * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ * Alexander Warg <warg@os.inf.tu-dresden.de>,
+ * Frank Mehnert <fm3@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#ifndef INIT_KIP_H__
+#define INIT_KIP_H__
+
+#include <l4/util/mb_info.h>
+#include "startup.h"
+#include "init_kip-arch.h"
+
+#ifdef __cplusplus
+class Region_list;
+
+void init_kip_f(void *_l4i, boot_info_t *bi, l4util_mb_info_t *mbi,
+ Region_list *ram, Region_list *regions);
+#endif
+
+#endif
--- /dev/null
+/**
+ * \file
+ */
+/*
+ * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ * Alexander Warg <warg@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <l4/sys/kip.h>
+#include <l4/util/l4_macros.h>
+#include "panic.h"
+
+#include "macros.h"
+#include "init_kip.h"
+#include "region.h"
+#include "startup.h"
+#include <l4/sys/kip>
+
+using L4::Kip::Mem_desc;
+
+/**
+ * setup Kernel Info Page
+ */
+void
+init_kip_f(void *_l4i, boot_info_t *bi, l4util_mb_info_t *mbi,
+ Region_list *ram, Region_list *regions)
+{
+ l4_kernel_info_t *l4i = (l4_kernel_info_t *)_l4i;
+
+ unsigned char l4_api = l4i->version >> 24;
+
+ if (l4_api != 0x87 /*VERSION_FIASCO*/)
+ panic("cannot load kernels other than Fiasco");
+
+ Mem_desc *md = Mem_desc::first(_l4i);
+ for (Region const* c = ram->begin(); c != ram->end(); ++c)
+ (md++)->set(c->begin(), c->end(), Mem_desc::Conventional);
+
+ for (Region const *c = regions->begin(); c != regions->end(); ++c)
+ {
+ Mem_desc::Mem_type type = Mem_desc::Reserved;
+ unsigned char sub_type = 0;
+ switch (c->type())
+ {
+ case Region::No_mem:
+ case Region::Ram:
+ case Region::Boot:
+ continue;
+ case Region::Kernel:
+ type = Mem_desc::Reserved;
+ break;
+ case Region::Sigma0:
+ type = Mem_desc::Dedicated;
+ break;
+ case Region::Root:
+ type = Mem_desc::Bootloader;
+ break;
+ case Region::Arch:
+ type = Mem_desc::Arch;
+ sub_type = c->sub_type();
+ break;
+ case Region::Info:
+ type = Mem_desc::Info;
+ sub_type = c->sub_type();
+ break;
+ }
+ (md++)->set(c->begin(), c->end() - 1, type, sub_type);
+ }
+
+ l4i->user_ptr = (unsigned long)mbi;
+
+ /* set up sigma0 info */
+ l4i->sigma0_eip = bi->sigma0_start;
+ printf(" Sigma0 config ip:" l4_addr_fmt " sp:" l4_addr_fmt "\n",
+ l4i->sigma0_eip, l4i->sigma0_esp);
+
+ /* set up roottask info */
+ l4i->root_eip = bi->roottask_start;
+ printf(" Roottask config ip:" l4_addr_fmt " sp:" l4_addr_fmt "\n",
+ l4i->root_eip, l4i->root_esp);
+
+ /* Platform info */
+ strncpy(l4i->platform_info.name, PLATFORM_TYPE,
+ sizeof(l4i->platform_info.name));
+ l4i->platform_info.name[sizeof(l4i->platform_info.name) - 1] = 0;
+}
--- /dev/null
+#pragma once
+
+#include <l4/sys/types.h>
+
+// To generate the kernel version:
+// perl -p -e 's/l4_uint(\d+)_t/Unsigned$1/;s/^#inc.+/#include "types.h"/' koptions-def.h
+
+namespace L4_kernel_options
+{
+ enum Flags
+ {
+ F_wait = 1 << 0,
+ F_serial_esc = 1 << 1,
+ F_noserial = 1 << 2,
+ F_noscreen = 1 << 3,
+ F_esc = 1 << 4,
+ F_nojdb = 1 << 5,
+ F_nokdb = 1 << 6,
+ F_nohlt = 1 << 7,
+ F_apic = 1 << 8,
+ F_loadcnt = 1 << 9,
+ F_watchdog = 1 << 10,
+ F_keymap_de = 1 << 11,
+ F_irq0 = 1 << 13,
+ F_nosfn = 1 << 15,
+ F_jdb_never_stop = 1 << 16,
+
+ F_kmemsize = 1 << 17,
+ F_tbuf_entries = 1 << 18,
+ F_out_buf = 1 << 19,
+ F_uart_baud = 1 << 20,
+ F_uart_base = 1 << 21,
+ F_uart_irq = 1 << 22,
+
+ F_jdb_cmd = 1 << 23,
+ };
+
+ enum
+ {
+ Magic = 0x4C344B43,
+ };
+
+ enum Uart_type
+ {
+ Uart_type_invalid = 0,
+ Uart_type_ioport = 1,
+ Uart_type_mmio = 2,
+ };
+
+ enum
+ {
+ Uart_irq_none = 0xffff,
+ };
+
+ struct Uart
+ {
+ l4_uint32_t base_baud; ///< Base baud rate of the UART (if applicable)
+ l4_uint32_t baud; ///< Baud rate (this is the baud rate to use)
+ l4_uint16_t irqno; ///< (Receive) IRQ
+ l4_uint8_t reg_shift; ///< Shift value for register addressing
+ l4_uint8_t access_type; ///< Accesstype of UART: unset, MMIO or ports
+ l4_uint64_t base_address; ///< Start address of UART
+ } __attribute__((packed));
+
+ struct Options
+ {
+ l4_uint32_t magic; ///< Magic value
+ l4_uint32_t version; ///< Version of this structure
+
+ l4_uint32_t flags; ///< Option flags
+
+ l4_uint32_t kmemsize; ///< Wanted kernel memory size in KiB
+
+ Uart uart; ///< Kernel UART
+
+ char jdb_cmd[128];
+ l4_uint32_t tbuf_entries;
+ l4_uint32_t out_buf;
+
+ l4_uint32_t opt(Flags flag) const { return flags & flag; }
+
+ } __attribute__((packed));
+};
--- /dev/null
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "koptions.h"
+
+static struct {
+ const char *s;
+ unsigned int flag;
+} boolean_opts[] = {
+ { " -wait", L4_kernel_options::F_wait },
+ { " -serial_esc", L4_kernel_options::F_serial_esc },
+ { " -noserial", L4_kernel_options::F_noserial },
+ { " -noscreen", L4_kernel_options::F_noscreen },
+ { " -esc", L4_kernel_options::F_esc },
+ { " -nojdb", L4_kernel_options::F_nojdb },
+ { " -nokdb", L4_kernel_options::F_nokdb },
+ { " -nohlt", L4_kernel_options::F_nohlt },
+ { " -apic", L4_kernel_options::F_apic },
+ { " -loadcnt", L4_kernel_options::F_loadcnt },
+ { " -watchdog", L4_kernel_options::F_watchdog },
+ { " -irq0", L4_kernel_options::F_irq0 },
+ { " -nosfn", L4_kernel_options::F_nosfn },
+ { " -jdb_never_stop", L4_kernel_options::F_jdb_never_stop },
+};
+
+static struct {
+ const char *s;
+ unsigned int flag;
+ unsigned int offset;
+} unsigned_opts[] = {
+ { " -kmemsize", L4_kernel_options::F_kmemsize,
+ offsetof(L4_kernel_options::Options, kmemsize) },
+ { " -tbuf_entries", L4_kernel_options::F_tbuf_entries,
+ offsetof(L4_kernel_options::Options, tbuf_entries) },
+ { " -out_buf", L4_kernel_options::F_out_buf,
+ offsetof(L4_kernel_options::Options, out_buf) },
+};
+
+#define MEMBERSIZE(type, member) sizeof(((type *)0)->member)
+
+static struct {
+ const char *s;
+ unsigned int flag;
+ unsigned int size;
+ unsigned int offset;
+} string_opts[] = {
+ { " -jdb_cmd", L4_kernel_options::F_jdb_cmd,
+ MEMBERSIZE(L4_kernel_options::Options, jdb_cmd),
+ offsetof(L4_kernel_options::Options, jdb_cmd) },
+};
+
+static void kcmdline_show(L4_kernel_options::Options *lko)
+{
+ printf("Location: %016lx Size: %zd Bytes\n",
+ (unsigned long)lko, sizeof(*lko));
+ printf("Flags: %08x\n", lko->flags);
+ for (unsigned i = 0; i < sizeof(boolean_opts) / sizeof(boolean_opts[0]); ++i)
+ {
+ if (lko->flags & boolean_opts[i].flag)
+ printf(" %s\n", boolean_opts[i].s);
+ }
+
+ if (lko->flags & L4_kernel_options::F_kmemsize)
+ printf("Kmemsize: %dKiB\n", lko->kmemsize);
+ if (lko->flags & L4_kernel_options::F_tbuf_entries)
+ printf("Tbuf entries: %d\n", lko->tbuf_entries);
+ if (lko->flags & L4_kernel_options::F_out_buf)
+ printf("Out bufs: %d\n", lko->out_buf);
+
+ if (lko->jdb_cmd[0])
+ printf("JDB command: %s\n", lko->jdb_cmd);
+}
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+void kcmdline_parse(char const *cmdline,
+ L4_kernel_options::Options *lko)
+{
+ if (0)
+ printf("Kernel command-line: %s\n", cmdline);
+
+ // boolean options
+ for (unsigned i = 0; i < ARRAY_SIZE(boolean_opts); ++i)
+ if (strstr(cmdline, boolean_opts[i].s))
+ lko->flags |= boolean_opts[i].flag;
+
+ // integer options
+ for (unsigned i = 0; i < ARRAY_SIZE(unsigned_opts); ++i)
+ {
+ char *c;
+ unsigned len = strlen(unsigned_opts[i].s);
+ if ((c = strstr(cmdline, unsigned_opts[i].s))
+ && (c[len] == ' ' || c[len] == '='))
+ {
+ lko->flags |= unsigned_opts[i].flag;
+ *(unsigned *)((char *)lko + unsigned_opts[i].offset)
+ = strtol(c + len + 1, 0, 0);
+ }
+ }
+
+ // string options
+ for (unsigned i = 0; i < ARRAY_SIZE(string_opts); ++i)
+ {
+ char *c;
+ unsigned len = strlen(string_opts[i].s);
+ if ((c = strstr(cmdline, string_opts[i].s))
+ && (c[len] == ' ' || c[len] == '='))
+ {
+ char *dst = (char *)lko + string_opts[i].offset;
+ lko->flags |= string_opts[i].flag;
+ c += len + 1;
+ while (*c && *c != ' '
+ && (dst < (char *)lko + string_opts[i].offset +
+ string_opts[i].size - 1))
+ *dst++ = *c++;
+ *dst = 0;
+ }
+ }
+
+ // warnings
+ if (strstr(cmdline, "-comport")
+ || strstr(cmdline, "-comspeed")
+ || strstr(cmdline, "-comirq"))
+ printf("WARNING: Command line options -comport, -comspeed and -comirq\n"
+ " have been moved to bootstrap and are shared beetween\n"
+ " Fiasco and bootstrap now. Please remove them from\n"
+ " your Fiasco command line, they do not have an effect\n"
+ " there.\n");
+
+ if (0)
+ kcmdline_show(lko);
+}
--- /dev/null
+#pragma once
+
+#include "koptions-def.h"
+
+void
+kcmdline_parse(char const *cmdline, L4_kernel_options::Options *lko);
--- /dev/null
+/* vi:ft=c
+ Common functionality for linker scripts in bootstrap */
+#define CTORS \
+ . = ALIGN(8); \
+ PROVIDE (__CTORS_BEGIN = .); \
+ KEEP (*(SORT(.ctors.*))) \
+ KEEP (*(.ctors)) \
+ PROVIDE (__CTORS_END = .); \
+ PROVIDE (__preinit_array_start = .); \
+ KEEP (*(SORT(.preinit_array.*))) \
+ KEEP (*(.preinit_array)) \
+ PROVIDE (__preinit_array_end = .); \
+ PROVIDE (__init_array_start = .); \
+ KEEP (*(SORT(.init_array.*))) \
+ KEEP (*(.init_array)) \
+ PROVIDE (__init_array_end = .);
+
+
+#define PLATFORMS \
+ PROVIDE (__PLATFORMS_BEGIN = .); \
+ KEEP (*(.platformdata)) \
+ PROVIDE (__PLATFORMS_END = .);
+
--- /dev/null
+/**
+ * \file bootstrap/server/src/libc_support.c
+ * \brief Support for C library
+ *
+ * \date 2004-2008
+ * \author Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ * Frank Mehnert <fm3@os.inf.tu-dresden.de> */
+
+/*
+ * (c) 2005-2009 Author(s)
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <strings.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/types.h>
+#include "panic.h"
+
+#include <l4/cxx/basic_ostream>
+
+#include "support.h"
+
+Platform_base *Platform_base::platform;
+
+static L4::Uart *stdio_uart;
+
+L4::Uart *uart()
+{ return stdio_uart; }
+
+void set_stdio_uart(L4::Uart *uart)
+{ stdio_uart = uart; }
+
+
+inline void *operator new (size_t, void *p) { return p; }
+// IO Stream backend
+namespace {
+
+ class BootstrapIOBackend : public L4::IOBackend
+ {
+ protected:
+ void write(char const *str, unsigned len);
+ };
+
+ void BootstrapIOBackend::write(char const *str, unsigned len)
+ {
+ ::write(STDOUT_FILENO, str, len);
+ }
+
+};
+
+namespace L4 {
+ typedef char Fake_iobackend[sizeof(BootstrapIOBackend)]
+ __attribute__((aligned(__alignof__(BootstrapIOBackend))));
+ typedef char Fake_ostream[sizeof(BasicOStream)]
+ __attribute__((aligned(__alignof__(BasicOStream))));
+
+ Fake_ostream cout;
+ Fake_ostream cerr;
+
+ static Fake_iobackend _iob;
+
+ void iostream_init();
+ void iostream_init()
+ {
+ static int _initialized;
+ if (!_initialized)
+ {
+ _initialized = 1;
+ BootstrapIOBackend *iob = new (&_iob) BootstrapIOBackend();
+ new (&cerr) BasicOStream(iob);
+ new (&cout) BasicOStream(iob);
+ }
+ }
+};
+
+typedef void Ctor();
+
+static void call_ctors(Ctor **start, Ctor **end)
+{
+ for (; start < end; ++start)
+ if (*start)
+ (*start)();
+}
+
+void
+ctor_init()
+{
+ extern Ctor *__CTORS_BEGIN[];
+ extern Ctor *__CTORS_END[];
+ extern Ctor *__init_array_start[];
+ extern Ctor *__init_array_end[];
+ extern Ctor *__preinit_array_start[];
+ extern Ctor *__preinit_array_end[];
+
+ call_ctors(__preinit_array_start, __preinit_array_end);
+ call_ctors(__CTORS_BEGIN, __CTORS_END);
+ call_ctors(__init_array_start, __init_array_end);
+}
+
+
+void exit(int c) throw()
+{
+ _exit(c);
+}
+
+void (*__exit_cleanup) (int) = 0;
+
+extern "C" void __attribute__((noreturn))
+__assert(const char *, const char *, int, register const char *);
+
+extern "C" void __attribute__((noreturn))
+__assert(const char *assertion, const char * filename,
+ int linenumber, register const char * function)
+{
+ printf("%s:%d: %s: Assertion `%s' failed.\n",
+ filename,
+ linenumber,
+ ((function == NULL) ? "?function?" : function),
+ assertion
+ );
+ panic("Assertion");
+ while(1)
+ ;
+}
+
+ssize_t
+write(int fd, const void *buf, size_t count)
+{
+ if (!uart())
+ return count;
+
+ if (fd == STDOUT_FILENO || fd == STDERR_FILENO)
+ {
+ char *b = (char *)buf;
+ int i = count;
+ while (i--)
+ {
+ char c = *b++;
+ if (c == '\n')
+ uart()->write("\r", 1);
+ uart()->write(&c, 1);
+ }
+
+ return count;
+ }
+
+ errno = EBADF;
+ return -1;
+}
+
+#undef getchar
+int
+getchar(void)
+{
+ int c;
+ if (!uart())
+ return -1;
+
+ do
+ c = uart()->get_char(0);
+ while (c == -1);
+ return c;
+}
+
+off_t lseek(int /*fd*/, off_t /*offset*/, int /*whence*/)
+{
+ return 0;
+}
+
+void *__dso_handle = &__dso_handle;
+
+extern "C" void reboot(void) __attribute__((noreturn));
+void reboot(void)
+{
+ void reboot_arch() __attribute__((noreturn));
+ reboot_arch();
+}
+
+extern "C" void __attribute__((noreturn))
+_exit(int /*rc*/)
+{
+ printf("\n\033[1mKey press reboots...\033[m\n");
+ getchar();
+ printf("Rebooting.\n\n");
+ reboot();
+}
+
+/** for assert */
+void
+abort(void) throw()
+{
+ _exit(1);
+}
+
+void
+panic(const char *fmt, ...)
+{
+ va_list v;
+ va_start (v, fmt);
+ vprintf(fmt, v);
+ va_end(v);
+ putchar('\n');
+ exit(1);
+}
--- /dev/null
+#include "support.h"
+
+unsigned long
+Memory::find_free_ram(unsigned long size,
+ unsigned long min_addr,
+ unsigned long max_addr)
+{
+ unsigned long min = min_addr;
+ if (min < sizeof(unsigned long long))
+ min = sizeof(unsigned long long);
+ for (Region *rr = ram->begin(); rr != ram->end(); ++rr)
+ {
+ if (min >= rr->end())
+ continue;
+
+ if (max_addr <= rr->begin())
+ continue;
+
+ if (min < rr->begin())
+ min = rr->begin();
+
+ unsigned long max = max_addr;
+ if (rr->end() < max)
+ max = rr->end();
+
+ Region search_area(min, max, "ram for modules");
+ unsigned long long to = regions->find_free(search_area, size, L4_PAGESHIFT);
+ if (to)
+ return to;
+ }
+ return 0;
+}
+
+unsigned long
+Memory::find_free_ram_rev(unsigned long size,
+ unsigned long min_addr,
+ unsigned long max_addr)
+{
+ if (min_addr < sizeof(unsigned long long))
+ min_addr = sizeof(unsigned long long);
+
+ unsigned long max = max_addr;
+ for (Region *rr = ram->end() - 1; rr >= ram->begin(); --rr)
+ {
+ if (min_addr >= rr->end())
+ continue;
+
+ if (max <= rr->begin())
+ continue;
+
+ unsigned long min = min_addr;
+ if (min < rr->begin())
+ min = rr->begin();
+
+ if (rr->end() < max)
+ max = rr->end();
+
+ Region search_area(min, max, "ram for modules");
+ unsigned long long to
+ = regions->find_free_rev(search_area, size, L4_PAGESHIFT);
+ if (to)
+ return to;
+ }
+ return 0;
+}
+
+
--- /dev/null
+#pragma once
+
+/// Info for each module
+struct Mod_info
+{
+ char const *start;
+ unsigned size;
+ unsigned size_uncompressed;
+ char const *name;
+ char const *cmdline;
+ char const *md5sum_compr;
+ char const *md5sum_uncompr;
+} __attribute__((packed));
--- /dev/null
+/*
+ * (c) 2008-2009 Frank Mehnert <fm3@os.inf.tu-dresden.de>,
+ * Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#include <stdio.h>
+#include "module.h"
+
+void
+print_module_name(const char *name, const char *alt_name)
+{
+ const char *c1, *c2;
+
+ if (!name)
+ {
+ printf("%s", alt_name);
+ return;
+ }
+
+ c2 = name;
+ while (*c2 != '\0' && *c2 != ' ')
+ c2++;
+ c1 = c2;
+ if (c1 > name)
+ c1--;
+ while (c1 > name && c2-c1 < 56)
+ c1--;
+
+ printf("%.*s", (unsigned)(c2-c1), c1);
+}
--- /dev/null
+/*
+ * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ * Alexander Warg <warg@os.inf.tu-dresden.de>,
+ * Frank Mehnert <fm3@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#ifndef MODULE_H
+#define MODULE_H
+
+#include <stddef.h>
+#include <l4/util/mb_info.h>
+#include <l4/sys/compiler.h>
+
+EXTERN_C_BEGIN
+
+void print_module_name(const char *name, const char *alt_name);
+
+EXTERN_C_END
+
+#endif
--- /dev/null
+/*
+ * (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#pragma once
+
+#ifdef __cplusplus
+extern "C"
+#endif
+void panic(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
+
--- /dev/null
+/**
+ * \file bootstrap/server/src/patch.c
+ * \brief Patching of boot modules
+ *
+ * \date 09/2005
+ * \author Frank Mehnert <fm3@os.inf.tu-dresden.de> */
+
+/*
+ * (c) 2005-2009 Author(s)
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <l4/sys/consts.h>
+#include <l4/util/mb_info.h>
+#include "panic.h"
+#include "macros.h"
+#include "types.h"
+#include "patch.h"
+#include "startup.h"
+
+
+/* search module in module list */
+static l4util_mb_mod_t*
+search_module(const char *name, size_t name_len, l4util_mb_info_t *mbi,
+ const char **cmdline)
+{
+ unsigned i;
+ const char *c = 0, *ce = 0;
+ l4util_mb_mod_t *mod;
+
+ for (i=0; i<mbi->mods_count; i++)
+ {
+ const char *m, *n;
+
+ mod = (L4_MB_MOD_PTR(mbi->mods_addr)) + i;
+ m = c = L4_CONST_CHAR_PTR(mod->cmdline);
+ ce = strchr(c, ' ');
+ if (!ce)
+ ce = c+strlen(c);
+ for (;;)
+ {
+ if (!(n = strchr(m, name[0])) || n+name_len>ce)
+ break;
+ if (!memcmp(name, n, name_len))
+ {
+ *cmdline = c;
+ return mod;
+ }
+ m = n+1;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Handle -patch=<module_name>,<variable>=blah parameter. Overwrite a specific
+ * module from command line. This allows to change the boot configuration (e.g.
+ * changing parameters of a loader script)
+ */
+void
+patch_module(const char **str, l4util_mb_info_t *mbi)
+{
+ const char *nam_beg, *nam_end;
+ const char *var_beg, *var_end;
+ const char *val_beg, *val_end;
+ char *mod_beg, *mod_end, *mod_ptr, quote = 0;
+ l4_size_t var_size, val_size, max_patch_size;
+ const char *cmdline = 0;
+ l4util_mb_mod_t *mod;
+
+ /* nam_beg ... nam_end */
+ nam_beg = *str+8;
+ nam_end = strchr(nam_beg, ',');
+ if (!nam_end || strpbrk(nam_beg, "\011 =*")-1 < nam_end)
+ panic("-patch: bad module name");
+
+ mod = search_module(nam_beg, nam_end-nam_beg, mbi, &cmdline);
+ if (!mod)
+ panic("-patch: cannot find module \"%.*s\"",
+ (int)(nam_end-nam_beg), nam_beg);
+
+ mod_beg = L4_CHAR_PTR(mod->mod_start);
+ mod_end = L4_CHAR_PTR(mod->mod_end);
+
+ /* How much bytes the module can be enlarged to. The module cannot
+ * be extended beyond page boundaries because the next module starts
+ * there and we don't want to move the following modules. */
+ max_patch_size = l4_round_page((l4_addr_t)mod_end) - (l4_addr_t)mod_end - 1;
+
+ printf(" Patching module \"%s\"\n", cmdline);
+
+ for (var_beg=nam_end; *var_beg==','; var_beg=*str)
+ {
+ var_beg++;
+ /* var_beg ... var_end */
+ var_end = strchr(var_beg, '=');
+ if (!var_end || strpbrk(var_beg, "\011 ,*")-1 < nam_end)
+ panic("-patch: bad variable name");
+ var_size = var_end-var_beg;
+
+ /* val_beg ... val_end, consider quotes */
+ val_beg = val_end = var_end+1;
+ if (*val_end == '"' || *val_end == '\'')
+ {
+ val_beg++;
+ quote = *val_end++;
+ }
+ while (*val_end && ((!quote && !isspace(*val_end) && *val_end!=',') ||
+ (quote && *val_end!=quote)))
+ val_end++;
+ *str = val_end;
+ if (quote)
+ (*str)++;
+ quote = 0;
+ val_size = val_end-val_beg;
+
+ /* replace all occurences of variable with value */
+ for (mod_ptr=mod_beg;;)
+ {
+ if (!(mod_ptr = (char *)memmem(mod_ptr, mod_end - mod_ptr,
+ var_beg, var_end - var_beg)))
+ break;
+ if (var_size < val_size && max_patch_size < val_size-var_size)
+ panic("-patch: not enough space in module");
+ max_patch_size += var_size - val_size;
+ memmove(mod_ptr+val_size, mod_ptr+var_size, mod_end-mod_ptr-var_size);
+ if (val_size < var_size)
+ memset(mod_end-var_size+val_size, 0, var_size-val_size);
+ memcpy(mod_ptr, val_beg, val_size);
+ mod_ptr += val_size;
+ mod_end += val_size - var_size;
+ }
+ }
+
+ mod->mod_end = (l4_addr_t)mod_end;
+}
+
+
+/**
+ * Handle -arg=<module_name>,blah parameter. Replace old command line
+ * parameters of <module_name> by blah. Useful for changing the boot
+ * configuration of a bootstrap image.
+ *
+ * Get a pointer to new argument and return the size.
+ */
+char *
+get_arg_module(char *cmdline, const char *name, unsigned *size)
+{
+ char *val_beg = NULL, *val_end;
+ char *s = cmdline;
+
+ if (!s)
+ return 0;
+
+ while (!val_beg && (s = strstr(s, " -arg=")))
+ {
+ char *a, *name_end;
+
+ s += 6;
+ name_end = strchr(s, ',');
+ if (!name_end)
+ panic("comma missing after modname in -arg=");
+ *name_end = 0;
+
+ for (a = s; *a; a++)
+ if (isspace(*a))
+ panic("Invalid '-arg=modname,text' parameter");
+
+ // we do a fuzzy name-match here
+ if (strstr(name, s))
+ val_beg = name_end+1;
+ *name_end = ',';
+ }
+ if (!val_beg)
+ return 0;
+
+ // consider quotes
+ unsigned char quote = 0;
+ if (*val_beg == '"' || *val_beg == '\'')
+ quote = *val_beg++;
+ val_end = val_beg;
+
+ while (*val_end && ((!quote && !isspace(*val_end)) || *val_end!=quote))
+ val_end++;
+
+ *size = val_end - val_beg;
+ return val_beg;
+}
--- /dev/null
+/*
+ * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ * Alexander Warg <warg@os.inf.tu-dresden.de>,
+ * Frank Mehnert <fm3@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#ifndef PATCH_H
+#define PATCH_H
+
+#include <l4/sys/compiler.h>
+
+EXTERN_C_BEGIN
+void
+patch_module(const char **str, l4util_mb_info_t *mbi);
+char *
+get_arg_module(char *cmdline, const char *name, unsigned *size);
+EXTERN_C_END
+
+#endif
--- /dev/null
+/*!
+ * \file
+ * \brief Support for Marvell Armada 38x
+ *
+ * \date 2015
+ * \author Adam Lackorzynski <adam@l4re.org>
+ *
+ */
+/*
+ * (c) 2015 Author(s)
+ *
+ * This file is part of L4Re and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include "support.h"
+#include "mmio_16550.h"
+
+namespace {
+class Platform_arm_armada38x : public Platform_single_region_ram
+{
+ bool probe() { return true; }
+
+ void init()
+ {
+ kuart.base_address = 0xf1012000;
+ kuart.base_baud = 15625000;
+ kuart.baud = 115200;
+ kuart.irqno = 44;
+ kuart.reg_shift = 2;
+ static L4::Uart_16550 _uart(kuart.base_baud, 0, 0, 0, 0);
+ setup_16550_mmio_uart(&_uart);
+ }
+};
+}
+
+REGISTER_PLATFORM(Platform_arm_armada38x);
--- /dev/null
+/*!
+ * \file
+ * \brief Support for Exynos platforms
+ *
+ * \author Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2013 Author(s)
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include "support.h"
+#include <l4/drivers/uart_s3c2410.h>
+
+#include <cstdio>
+
+namespace {
+class Platform_arm_exynos : public Platform_single_region_ram
+{
+public:
+ bool probe() { return true; }
+
+ void init()
+ {
+ static L4::Uart_s5pv210 _uart;
+ const unsigned long uart_offset = 0x10000;
+ unsigned long uart_base;
+ unsigned uart_nr = PLATFORM_UART_NR;
+
+#ifdef PLATFORM_TYPE_exynos4
+ uart_base = 0x13800000;
+#else
+ uart_base = 0x12c00000;
+#endif
+
+ static L4::Io_register_block_mmio r(uart_base + uart_nr * uart_offset);
+ _uart.startup(&r);
+ set_stdio_uart(&_uart);
+ }
+
+ void reboot()
+ {
+#ifdef PLATFORM_TYPE_exynos4
+ *(unsigned *)0x10020400 = 1;
+#else
+ *(unsigned *)0x10040400 = 1;
+#endif
+ }
+
+};
+}
+
+REGISTER_PLATFORM(Platform_arm_exynos);
--- /dev/null
+/*!
+ * \file support_imx.cc
+ * \brief Support for the i.MX platform
+ *
+ * \date 2008-02-04
+ * \author Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2008-2009 Author(s)
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include "support.h"
+#include <l4/drivers/uart_imx.h>
+
+namespace {
+class Platform_arm_imx : public Platform_single_region_ram
+{
+ bool probe() { return true; }
+
+ void init()
+ {
+#ifdef PLATFORM_TYPE_imx21
+ static L4::Io_register_block_mmio r(0x1000A000);
+ static L4::Uart_imx21 _uart;
+#elif defined(PLATFORM_TYPE_imx35)
+ static L4::Uart_imx35 _uart;
+ unsigned long uart_base;
+ switch (PLATFORM_UART_NR) {
+ default:
+ case 1: uart_base = 0x43f90000; break;
+ case 2: uart_base = 0x43f94000; break;
+ case 3: uart_base = 0x5000c000; break;
+ }
+ static L4::Io_register_block_mmio r(uart_base);
+#elif defined(PLATFORM_TYPE_imx51)
+ static L4::Io_register_block_mmio r(0x73fbc000);
+ static L4::Uart_imx51 _uart;
+#elif defined(PLATFORM_TYPE_imx6)
+ unsigned long uart_base;
+ switch (PLATFORM_UART_NR) {
+ case 1: uart_base = 0x02020000; break;
+ default:
+ case 2: uart_base = 0x021e8000; break;
+ };
+ static L4::Io_register_block_mmio r(uart_base);
+ static L4::Uart_imx6 _uart;
+#else
+#error Which platform type?
+#endif
+ _uart.startup(&r);
+ set_stdio_uart(&_uart);
+ }
+};
+}
+
+REGISTER_PLATFORM(Platform_arm_imx);
--- /dev/null
+/*!
+ * \file support_integrator.cc
+ * \brief Support for the integrator platform
+ *
+ * \date 2008-01-02
+ * \author Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2008-2009 Author(s)
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include "support.h"
+#include <l4/drivers/uart_pl011.h>
+
+namespace {
+class Platform_arm_int : public Platform_single_region_ram
+{
+ bool probe() { return true; }
+
+ void init()
+ {
+ static L4::Io_register_block_mmio r(0x16000000);
+ static L4::Uart_pl011 _uart(24019200);
+ _uart.startup(&r);
+ set_stdio_uart(&_uart);
+ }
+};
+}
+
+REGISTER_PLATFORM(Platform_arm_int);
--- /dev/null
+/*!
+ * \file support_kirkwood.cc
+ * \brief Support for the kirkwood platform
+ *
+ * \date 2010-11
+ * \author Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2010 Author(s)
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include "support.h"
+#include "mmio_16550.h"
+
+namespace {
+class Platform_arm_kirkwood : public Platform_single_region_ram
+{
+ bool probe() { return true; }
+
+ void init()
+ {
+ kuart.base_address = 0xf1012000; /* uart 1: 0xf1012100 */
+ kuart.reg_shift = 2;
+ kuart.base_baud = 12500000;
+ kuart.baud = 115200;
+ kuart.irqno = 33; /* uart 1 irq: ??? */
+ static L4::Uart_16550 _uart(kuart.base_baud, 0, 0, 0, 0);
+ setup_16550_mmio_uart(&_uart);
+
+
+ // SPI init, as there's an interrupt pending when coming from u-boot on
+ // the dockstar, so make it go away
+ *(unsigned *)0xf1010600 = 0; // disable
+ *(unsigned *)0xf1010614 = 0; // mask interrupt
+ *(unsigned *)0xf1010610 = 1; // clear interrupt
+ }
+};
+}
+
+REGISTER_PLATFORM(Platform_arm_kirkwood);
--- /dev/null
+/**
+ * \file support_sparc_leon3.cc
+ * \brief Support for the Sparc LEON3 platform
+ *
+ * \date 2010
+ * \author Björn Döbel <doebel@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2010 Author(s)
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include <l4/drivers/uart_leon3.h>
+
+#include "support.h"
+
+namespace {
+class Platform_leon3 :
+ public Platform_base,
+ public Boot_modules_image_mode
+{
+ bool probe() { return true; }
+ Boot_modules *modules() { return this; }
+
+ enum {
+ LEON3_NUM_DEVICE_INFO = 64,
+
+ LEON3_APBUART = 0x80000100,
+
+ LEON3_VENDOR_GAISLER = 0x1,
+ LEON3_VENDOR_ESA = 0x4,
+ LEON3_DEVICEID_MCTRL = 0xF,
+
+ LEON3_AHB_BAR_MASK_SHIFT = 4,
+ LEON3_AHB_BAR_MASK_MASK = 0xFFF,
+ LEON3_AHB_BAR_ADDR_SHIFT = 20,
+ LEON3_AHB_BAR_ADDR_MASK = 0xFFF,
+
+ LEON3_MEMCFG2 = 0x80000004,
+ LEON3_MEMCFG2_SDRAMSZ_SHIFT = 23,
+ LEON3_MEMCFG2_SDRAMSZ_MASK = 7,
+ LEON3_MEMCFG2_RAMSZ_SHIFT = 9,
+ LEON3_MEMCFG2_SRAM_DISABLEF = 13,
+ LEON3_MEMCFG2_RAMSZ_MASK = 0xF,
+
+ AHB_MASTER_TABLE = 0xFFFFF000,
+ AHB_SLAVE_TABLE = 0xFFFFF800,
+ };
+
+ long _ram_area_start;
+ long _ram_area_size;
+
+ void init()
+ {
+ static L4::Uart_leon3 _uart;
+ static L4::Io_register_block_mmio r(LEON3_APBUART); // XXX hard
+ _uart.startup(&r);
+ set_stdio_uart(&_uart);
+
+ puts("Scanning AHB masters...");
+ unsigned *idx = (unsigned*)AHB_MASTER_TABLE;
+ while (*idx != 0)
+ {
+ check_device(idx);
+ }
+
+ puts("Scanning AHB slaves...");
+ idx = (unsigned*)AHB_SLAVE_TABLE;
+ while (*idx != 0)
+ {
+ check_device(idx);
+ }
+ }
+
+
+ void check_device(unsigned *&ahb_idx)
+ {
+ short vendor = (*ahb_idx >> 24) & 0xF;
+ short dev = (*ahb_idx >> 12) & 0xFFF;
+
+ /* Special check: default RAM memory controller -> find out where the RAM area lies and
+ * how large it is configured to be */
+ if ((vendor == (short)LEON3_VENDOR_ESA) && (dev == (short)LEON3_DEVICEID_MCTRL))
+ {
+ unsigned bar2_addr = (*(ahb_idx+6) >> LEON3_AHB_BAR_ADDR_SHIFT) & LEON3_AHB_BAR_ADDR_MASK;
+ unsigned bar2_mask = (*(ahb_idx+6) >> LEON3_AHB_BAR_MASK_SHIFT) & LEON3_AHB_BAR_MASK_MASK;
+ _ram_area_start = bar2_addr << 20;
+ _ram_area_size = ~(bar2_mask << 20);
+ printf("RAM AREA: [%08lx - %08lx]\n",
+ _ram_area_start, _ram_area_start + _ram_area_size);
+ }
+ print_device(ahb_idx);
+ }
+
+ void print_device(unsigned *&ahb_idx)
+ {
+ short dev = (*ahb_idx >> 24) & 0xF;
+ short vendor = (*ahb_idx >> 12) & 0xFFF;
+ printf("dev:vendor %04hx:%04hx\n", dev, vendor);
+ printf("%08x %08x %08x %08x\n", *ahb_idx, *(ahb_idx+1), *(ahb_idx+2), *(ahb_idx+3));
+ ahb_idx += 4;
+ printf("%08x %08x %08x %08x\n", *ahb_idx, *(ahb_idx+1), *(ahb_idx+2), *(ahb_idx+3));
+ ahb_idx += 4;
+ printf("--------------------------------------\n");
+ }
+
+ void setup_memory_map()
+ {
+ /* § 10.8.2
+ SDRAM area is mapped into the upper half of the RAM area defined by BAR2
+ register. When the SDRAM enable bit is set in MCFG2, the controller is
+ enabled and mapped into upper half of the RAM area as long as the SRAM
+ disable bit is not set. If the SRAM disable bit is set, all access to
+ SRAM is disabled and the SDRAM banks are mapped into the lower half of
+ the RAM area.
+ */
+ unsigned mcfg2 = *(unsigned*)LEON3_MEMCFG2;
+ unsigned ram_size = (mcfg2 >> LEON3_MEMCFG2_RAMSZ_SHIFT) & LEON3_MEMCFG2_RAMSZ_MASK;
+ unsigned sdram_size = (mcfg2 >> LEON3_MEMCFG2_SDRAMSZ_SHIFT) & LEON3_MEMCFG2_SDRAMSZ_MASK;
+
+ sdram_size = 4 << sdram_size;
+
+ long sdram_base = _ram_area_start;
+ if (!(mcfg2 & LEON3_MEMCFG2_SRAM_DISABLEF))
+ sdram_base = _ram_area_start + ((_ram_area_size + 1) >> 1);
+
+#ifdef RAM_SIZE_MB
+ sdram_size = RAM_SIZE_MB;
+ sdram_base = RAM_BASE;
+#endif
+
+ printf("RAM: %4d kB\n", (8192 << ram_size) / 1024);
+ printf("SDRAM: %4d MB\n", sdram_size);
+
+ mem_manager->ram->add(Region::n(sdram_base, sdram_base + (sdram_size << 20),
+ ".sdram", Region::Ram));
+ }
+};
+}
+
+REGISTER_PLATFORM(Platform_leon3);
--- /dev/null
+#include <startup.h>
+#include "support.h"
+#include <l4/drivers/uart_16550.h>
+
+static void setup_16550_mmio_uart(L4::Uart_16550 *uart)
+{
+ kuart.access_type = L4_kernel_options::Uart_type_mmio;
+ static L4::Io_register_block_mmio r(kuart.base_address, kuart.reg_shift);
+ uart->startup(&r);
+ uart->change_mode(3, kuart.baud);
+ set_stdio_uart(uart);
+
+ kuart_flags |= L4_kernel_options::F_uart_base
+ | L4_kernel_options::F_uart_baud;
+
+ if (kuart.irqno != L4_kernel_options::Uart_irq_none)
+ kuart_flags |= L4_kernel_options::F_uart_irq;
+}
--- /dev/null
+/**
+ * \file
+ * \brief Support for the MPC52000
+ *
+ * \date 2009-02-16
+ * \author Sebastian Sumpf <sumpf@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2009 Author(s)
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include "support.h"
+#include <l4/drivers/uart_of.h>
+#include <l4/drivers/of_if.h>
+#include <l4/drivers/of_dev.h>
+
+namespace {
+class Platform_ppc_mpc52000 :
+ public Platform_base,
+ public Boot_modules_image_mode
+{
+ bool probe() { return true; }
+ Boot_modules *modules() { return this; }
+
+ void boot_kernel(unsigned long entry)
+ {
+ typedef void (*func)(l4util_mb_info_t *, unsigned long);
+ L4_drivers::Of_if of_if;
+ of_if.boot_finish();
+ ((func)entry)(0, of_if.get_prom());
+ exit(-100);
+ }
+
+ void init()
+ {
+ static L4::Uart_of _uart;
+ static L4::Io_register_block_mmio r(0);
+ _uart.startup(&r);
+ set_stdio_uart(&_uart);
+ }
+
+ void setup_memory_map()
+ {
+ L4_drivers::Of_if of_if;
+
+ printf(" Detecting ram size ...\n");
+ unsigned long ram_size = of_if.detect_ramsize();
+ printf(" Total memory size is %luMB\n", ram_size / (1024 * 1024));
+ mem_manager->ram->add(Region::n(0x0, ram_size, ".ram", Region::Ram));
+
+ // FIXME: move this somewhere else, it has mothing to do with
+ // memory setup
+#if 0
+ /* detect OF devices */
+ unsigned long drives_addr, drives_length;
+
+ if (of_if.detect_devices(&drives_addr, &drives_length))
+ {
+ mbi->flags |= L4UTIL_MB_DRIVE_INFO;
+ mbi->drives_addr = drives_addr;
+ mbi->drives_length = drives_length;
+ }
+#endif
+ }
+};
+}
+
+REGISTER_PLATFORM(Platform_ppc_mpc52000);
--- /dev/null
+/**
+ * \file support_om.cc
+ * \brief Support for the OpenMoko platform
+ *
+ * \date 2008
+ * \author Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2008-2009 Author(s)
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+
+#include "support.h"
+
+#include <l4/drivers/uart_s3c2410.h>
+#include <l4/drivers/uart_dummy.h>
+
+namespace {
+class Platform_arm_om : public Platform_single_region_ram
+{
+ bool probe() { return true; }
+
+ void init()
+ {
+ static L4::Uart_s3c2410 _uart;
+ static L4::Io_register_block_mmio r(0x50000000);
+ _uart.startup(&r);
+ set_stdio_uart(&_uart);
+ }
+};
+}
+
+REGISTER_PLATFORM(Platform_arm_om);
--- /dev/null
+/*!
+ * \file support_beagleboard.cc
+ * \brief Support for the Beagleboard
+ *
+ * \date 2009-08
+ * \author Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2009 Author(s)
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include "support.h"
+#include <l4/drivers/uart_omap35x.h>
+
+namespace {
+class Platform_arm_omap : public Platform_single_region_ram
+{
+ bool probe() { return true; }
+
+ void init()
+ {
+ static L4::Uart_omap35x _uart;
+#ifdef PLATFORM_TYPE_beagleboard
+ static L4::Io_register_block_mmio r(0x49020000);
+#elif defined(PLATFORM_TYPE_omap3evm)
+ static L4::Io_register_block_mmio r(0x4806a000);
+#elif defined(PLATFORM_TYPE_omap3_am33xx)
+ static L4::Io_register_block_mmio r(0x44e09000);
+#elif defined(PLATFORM_TYPE_pandaboard) || defined(PLATFORM_TYPE_omap5)
+ static L4::Io_register_block_mmio r(0x48020000);
+#else
+#error Unknown platform
+#endif
+ _uart.startup(&r);
+ set_stdio_uart(&_uart);
+ }
+
+ void arm_switch_to_hyp()
+ {
+ register l4_umword_t f asm("r12") = 0x102;
+ asm volatile("push {fp} \n"
+ "mcr p15, 0, sp, c13, c0, 2\n"
+ "mov r0, pc \n"
+ ".inst 0xe1600071 \n"
+ "mrc p15, 0, sp, c13, c0, 2\n"
+ "pop {fp} \n"
+ :
+ : "r" (f)
+ : "r0", "r1", "r2", "r3", "r4",
+ "r5", "r6", "r7", "r8", "r9",
+ "r10", "memory");
+ }
+};
+}
+
+REGISTER_PLATFORM(Platform_arm_omap);
--- /dev/null
+/*!
+ * \file support_pxa.cc
+ * \brief Support for the PXA platform
+ *
+ * \date 2008-01-04
+ * \author Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2008-2009 Author(s)
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include "mmio_16550.h"
+#include "support.h"
+
+namespace {
+class Platform_arm_pxa : public Platform_single_region_ram
+{
+ bool probe() { return true; }
+
+ void init()
+ {
+ kuart.base_address = 0x40100000;
+ kuart.reg_shift = 2;
+ kuart.base_baud = L4::Uart_16550::Base_rate_pxa;
+ kuart.baud = 115200;
+ kuart.irqno = -1;
+ static L4::Uart_16550 _uart(kuart.base_baud, 0, 1 << 6, 0, 0);
+ setup_16550_mmio_uart(&_uart);
+ }
+};
+}
+
+REGISTER_PLATFORM(Platform_arm_pxa);
--- /dev/null
+/*!
+ * \file rpi.cc
+ * \brief Support for the Raspberry Pi
+ *
+ * \date 2013
+ * \author Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2013 Author(s)
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include "support.h"
+#include <l4/drivers/uart_pl011.h>
+
+namespace {
+
+class Platform_arm_rpi : public Platform_single_region_ram
+{
+ bool probe() { return true; }
+
+ void init()
+ {
+ static L4::Io_register_block_mmio r(0x20201000);
+ static L4::Uart_pl011 _uart(3000000);
+ _uart.startup(&r);
+ set_stdio_uart(&_uart);
+ }
+};
+}
+
+REGISTER_PLATFORM(Platform_arm_rpi);
--- /dev/null
+/*!
+ * \file
+ * \brief Support for the rv platform
+ *
+ * \date 2011
+ * \author Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2008-2011 Author(s)
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include "support.h"
+
+#include <l4/drivers/uart_pl011.h>
+
+namespace {
+
+class Platform_arm_rv : public Platform_single_region_ram
+{
+ bool probe() { return true; }
+ void init()
+ {
+ static L4::Io_register_block_mmio r(0x10009000);
+ static L4::Uart_pl011 _uart(24019200);
+ _uart.startup(&r);
+ set_stdio_uart(&_uart);
+ }
+};
+
+}
+
+REGISTER_PLATFORM(Platform_arm_rv);
--- /dev/null
+/*!
+ * \file
+ * \brief Support for the rv platform
+ *
+ * \date 2011
+ * \author Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2008-2011 Author(s)
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include "support.h"
+
+#include <l4/drivers/uart_pl011.h>
+
+namespace {
+
+class Platform_arm_rv_vexpress : public Platform_single_region_ram
+{
+ bool probe() { return true; }
+ void init()
+ {
+ unsigned long m;
+ unsigned long uart_base = 0x10009000;
+
+ asm volatile("mrc p15, 0, %0, c0, c0, 0" : "=r" (m));
+ if ((m & 0x00000070) == 0x70)
+ uart_base = 0x1c090000;
+
+ static L4::Io_register_block_mmio r(uart_base);
+ static L4::Uart_pl011 _uart(24019200);
+ _uart.startup(&r);
+ set_stdio_uart(&_uart);
+ }
+};
+
+}
+
+REGISTER_PLATFORM(Platform_arm_rv_vexpress);
--- /dev/null
+/*!
+ * \file support_sa1000.cc
+ * \brief Support for SA1000 platform
+ *
+ * \date 2008-01-02
+ * \author Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2008-2009 Author(s)
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include "support.h"
+#include <l4/drivers/uart_sa1000.h>
+
+namespace {
+class Platform_arm_sa1000 : public Platform_single_region_ram
+{
+ bool probe() { return true; }
+
+ void init()
+ {
+ static L4::Uart_sa1000 _uart;
+ static L4::Io_register_block_mmio r(0x80010000);
+ //static L4::Io_register_block_mmio r(0x80050000);
+ _uart.startup(&r);
+ set_stdio_uart(&_uart);
+ }
+};
+}
+
+REGISTER_PLATFORM(Platform_arm_sa1000);
--- /dev/null
+
+/*!
+ * \file
+ * \brief Support for sunxi platforms
+ *
+ * \date 2013
+ * \author Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2013 Author(s)
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include "support.h"
+#include "mmio_16550.h"
+
+namespace {
+class Platform_arm_sunxi : public Platform_single_region_ram
+{
+ bool probe() { return true; }
+
+ void init()
+ {
+ kuart.base_address = 0x01c28000;
+ kuart.reg_shift = 2;
+ kuart.base_baud = 1500000;
+ kuart.baud = 115200;
+ kuart.irqno = 33;
+ static L4::Uart_16550 _uart(kuart.base_baud, 0, 0, 0, 0);
+ setup_16550_mmio_uart(&_uart);
+ }
+};
+}
+
+REGISTER_PLATFORM(Platform_arm_sunxi);
--- /dev/null
+/*!
+ * \file
+ * \brief Support for Tegra 2 platforms
+ *
+ * \date 2010-05
+ * \author Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2010 Author(s)
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+/* Init-code from http://android.git.kernel.org/?p=kernel/tegra.git */
+
+#include "support.h"
+#include "mmio_16550.h"
+
+namespace {
+class Platform_arm_tegra2 : public Platform_single_region_ram
+{
+ void some_delay(int d) const
+ {
+ for (int i = 0; i < d; i++)
+ asm volatile("":::"memory");
+ }
+
+ bool probe() { return true; }
+
+ void init()
+ {
+ volatile unsigned long *addr;
+
+ addr = (volatile unsigned long *)0x600060a0;
+ *addr = 0x5011b00c;
+
+ /* PLLP_OUTA_0 */
+ addr = (volatile unsigned long *)0x600060a4;
+ *addr = 0x10031c03;
+
+ /* PLLP_OUTB_0 */
+ addr = (volatile unsigned long *)0x600060a8;
+ *addr = 0x06030a03;
+
+ /* PLLP_MISC_0 */
+ addr = (volatile unsigned long *)0x600060ac;
+ *addr = 0x00000800;
+
+ some_delay(1000000);
+
+ /* UARTD clock source is PLLP_OUT0 */
+ addr = (volatile unsigned long *)0x600061c0;
+ *addr = 0;
+
+ /* Enable clock to UARTD */
+ addr = (volatile unsigned long *)0x60006018;
+ *addr |= 2;
+ some_delay(5000);
+
+ /* Deassert reset to UARTD */
+ addr = (volatile unsigned long *)0x6000600c;
+ *addr &= ~2;
+
+ some_delay(5000);
+
+ kuart.base_address = 0x70006300;
+ kuart.reg_shift = 2;
+ kuart.base_baud = 13478400;
+ kuart.baud = 115200;
+ kuart.irqno = 122;
+ static L4::Uart_16550 _uart(kuart.base_baud, 0, 0, 0, 0);
+ setup_16550_mmio_uart(&_uart);
+ }
+};
+}
+
+REGISTER_PLATFORM(Platform_arm_tegra2);
--- /dev/null
+/*!
+ * \file
+ * \brief Support for Tegra 3 platforms
+ *
+ * \date 2013
+ * \author Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2013 Author(s)
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include "support.h"
+#include "mmio_16550.h"
+
+namespace {
+class Platform_arm_tegra3 : public Platform_single_region_ram
+{
+ bool probe() { return true; }
+
+ void init()
+ {
+ switch (PLATFORM_UART_NR)
+ {
+ case 0:
+ kuart.base_address = 0x70006000;
+ kuart.irqno = 68;
+ break;
+ default:
+ case 2:
+ kuart.base_address = 0x70006200;
+ kuart.irqno = 78;
+ break;
+ };
+ kuart.reg_shift = 2;
+ kuart.base_baud = 25459200;
+ kuart.baud = 115200;
+
+ static L4::Uart_16550 _uart(kuart.base_baud, 0, 0, 0, 0);
+ setup_16550_mmio_uart(&_uart);
+ }
+};
+}
+
+REGISTER_PLATFORM(Platform_arm_tegra3);
--- /dev/null
+#include "support.h"
+#include "x86_pc-base.h"
+#include <string.h>
+
+#include "startup.h"
+#include "panic.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <efi.h>
+#include <efilib.h>
+#include <l4/util/irq.h> // l4util_cli
+
+namespace {
+
+static inline Region
+new_region(EFI_MEMORY_DESCRIPTOR const *td, char const *name,
+ Region::Type type, char sub = 0)
+{
+ return Region::n(td->PhysicalStart,
+ td->PhysicalStart + (0x1000 * td->NumberOfPages),
+ name, type, sub);
+}
+
+class Platform_x86_efi : public Platform_x86,
+ public Boot_modules_image_mode
+{
+public:
+ Boot_modules *modules() { return this; }
+
+ void init_efi(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
+ {
+ efi_image = image;
+ efi_systab = systab;
+
+ InitializeLib(efi_image, efi_systab);
+ }
+
+ void setup_memory_map()
+ {
+ UINTN num_entries;
+ UINTN key;
+ UINTN desc_size;
+ uint32_t desc_ver;
+
+ EFI_MEMORY_DESCRIPTOR *efi_mem_desc
+ = LibMemoryMap(&num_entries, &key, &desc_size, &desc_ver);
+
+ void *table;
+ EFI_GUID Acpi20TableGuid = ACPI_20_TABLE_GUID;
+ EFI_STATUS exit_status
+ = LibGetSystemConfigurationTable(&Acpi20TableGuid, &table);
+
+ if (exit_status != EFI_SUCCESS)
+ exit_status = LibGetSystemConfigurationTable(&AcpiTableGuid, &table);
+
+ if (exit_status != EFI_SUCCESS)
+ printf("No RDSP found in EFI system table\n");
+
+ exit_status = (EFI_STATUS)uefi_call_wrapper((void*)(BS->ExitBootServices), 2, efi_image, key);
+ if (exit_status != EFI_SUCCESS)
+ printf("EFI, ExitBootServices failed: %u\n", (unsigned)exit_status);
+ else
+ printf("Successfully exited EFI boot services.\n");
+
+ // UEFI may have enabled interrupts because of loaded device drivers
+ // Fiasco boot protocol requires interrupts to be disabled
+ l4util_cli();
+
+ enum
+ {
+ Acpi_rdsp = 0,
+ Acpi = 3,
+ Nvs = 4,
+ };
+
+
+ Region_list *ram = mem_manager->ram;
+ Region_list *regions = mem_manager->regions;
+
+ void *const map_end = (char *)efi_mem_desc + num_entries * desc_size;
+ for (char *d = (char *)efi_mem_desc; d < map_end; d += desc_size)
+ {
+ EFI_MEMORY_DESCRIPTOR *td = (EFI_MEMORY_DESCRIPTOR *)d;
+
+ switch (td->Type)
+ {
+ case EfiLoaderCode:
+ case EfiLoaderData:
+ case EfiBootServicesCode:
+ case EfiBootServicesData:
+ case EfiConventionalMemory:
+ ram->add(new_region(td, ".ram", Region::Ram));
+ break;
+ case EfiACPIReclaimMemory: // memory holds ACPI tables
+ regions->add(new_region(td, ".ACPI", Region::Arch, Acpi));
+ break;
+ case EfiACPIMemoryNVS: // memory reserved by firmware
+ regions->add(new_region(td, ".ACPI", Region::Arch, Nvs));
+ break;
+ }
+ }
+
+ // add region for ACPI tables
+ regions->add(Region::n(l4_trunc_page((l4_addr_t)table),
+ l4_trunc_page((l4_addr_t)table) + L4_PAGESIZE,
+ ".ACPI", Region::Info, Acpi_rdsp), true);
+
+ // merge adjacent regions
+ ram->optimize();
+ }
+
+private:
+ EFI_HANDLE efi_image;
+ EFI_SYSTEM_TABLE *efi_systab;
+};
+
+Platform_x86_efi _x86_pc_platform;
+}
+
+extern "C" EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab);
+EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
+{
+ _x86_pc_platform.init_efi(image, systab);
+ ctor_init();
+ Platform_base::platform = &_x86_pc_platform;
+ _x86_pc_platform.init();
+ _x86_pc_platform.setup_uart(_mbi_cmdline);
+ startup(_mbi_cmdline);
+
+ return EFI_SUCCESS;
+}
+
--- /dev/null
+#include "support.h"
+#include "startup.h"
+
+#include <l4/drivers/uart_16550.h>
+#include <l4/drivers/io_regblock_port.h>
+
+#include <string.h>
+#include "base_critical.h"
+#include "panic.h"
+
+#include <l4/util/cpu.h>
+#include <l4/util/port_io.h>
+#include <l4/cxx/static_container>
+
+#include <cassert>
+#include <cstdio>
+
+/** VGA console output */
+
+static void vga_init()
+{
+ /* Reset any scrolling */
+ l4util_out32(0xc, 0x3d4);
+ l4util_out32(0, 0x3d5);
+ l4util_out32(0xd, 0x3d4);
+ l4util_out32(0, 0x3d5);
+}
+
+static void vga_putchar(unsigned char c)
+{
+ static int ofs = -1, esc, esc_val, attr = 0x07;
+ unsigned char *vidbase = (unsigned char*)0xb8000;
+
+ base_critical_enter();
+
+ if (ofs < 0)
+ {
+ /* Called for the first time - initialize. */
+ ofs = 80*2*24;
+ vga_putchar('\n');
+ }
+
+ switch (esc)
+ {
+ case 1:
+ if (c == '[')
+ {
+ esc++;
+ goto done;
+ }
+ esc = 0;
+ break;
+
+ case 2:
+ if (c >= '0' && c <= '9')
+ {
+ esc_val = 10*esc_val + c - '0';
+ goto done;
+ }
+ if (c == 'm')
+ {
+ attr = esc_val ? 0x0f : 0x07;
+ goto done;
+ }
+ esc = 0;
+ break;
+ }
+
+ switch (c)
+ {
+ case '\n':
+ memmove(vidbase, vidbase+80*2, 80*2*24);
+ memset(vidbase+80*2*24, 0, 80*2);
+ /* fall through... */
+ case '\r':
+ ofs = 0;
+ break;
+
+ case '\t':
+ ofs = (ofs + 8) & ~7;
+ break;
+
+ case '\033':
+ esc = 1;
+ esc_val = 0;
+ break;
+
+ default:
+ /* Wrap if we reach the end of a line. */
+ if (ofs >= 80)
+ vga_putchar('\n');
+
+ /* Stuff the character into the video buffer. */
+ {
+ volatile unsigned char *p = vidbase + 80*2*24 + ofs*2;
+ p[0] = c;
+ p[1] = attr;
+ ofs++;
+ }
+ break;
+ }
+
+done:
+ base_critical_leave();
+}
+
+/** Poor man's getchar, only returns raw scan code. We don't need to know
+ * _which_ key was pressed, we only want to know _if_ a key was pressed. */
+static int raw_keyboard_getscancode(void)
+{
+ unsigned status, scan_code;
+
+ base_critical_enter();
+
+ l4util_cpu_pause();
+
+ /* Wait until a scan code is ready and read it. */
+ status = l4util_in8(0x64);
+ if ((status & 0x01) == 0)
+ {
+ base_critical_leave();
+ return -1;
+ }
+ scan_code = l4util_in8(0x60);
+
+ /* Drop mouse events */
+ if ((status & 0x20) != 0)
+ {
+ base_critical_leave();
+ return -1;
+ }
+
+ base_critical_leave();
+ return scan_code;
+}
+
+
+static inline l4_uint32_t
+pci_conf_addr(l4_uint32_t bus, l4_uint32_t dev, l4_uint32_t fn, l4_uint32_t reg)
+{ return 0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3); }
+
+static l4_uint32_t pci_read(unsigned char bus, l4_uint32_t dev,
+ l4_uint32_t fn, l4_uint32_t reg,
+ unsigned char width)
+{
+ l4util_out32(pci_conf_addr(bus, dev, fn, reg), 0xcf8);
+
+ switch (width)
+ {
+ case 8: return l4util_in8(0xcfc + (reg & 3));
+ case 16: return l4util_in16((0xcfc + (reg & 3)) & ~1UL);
+ case 32: return l4util_in32(0xcfc);
+ }
+ return 0;
+}
+
+static void pci_write(unsigned char bus, l4_uint32_t dev,
+ l4_uint32_t fn, l4_uint32_t reg,
+ l4_uint32_t val, unsigned char width)
+{
+ l4util_out32(pci_conf_addr(bus, dev, fn, reg), 0xcf8);
+
+ switch (width)
+ {
+ case 8: l4util_out8(val, 0xcfc + (reg & 3)); break;
+ case 16: l4util_out16(val, (0xcfc + (reg & 3)) & ~1UL); break;
+ case 32: l4util_out32(val, 0xcfc); break;
+ }
+}
+
+
+namespace {
+
+struct Resource
+{
+ enum Type { NO_BAR, IO_BAR, MEM_BAR };
+ Type type;
+ unsigned long base;
+ unsigned long len;
+ Resource() : type(NO_BAR) {}
+};
+
+enum { NUM_BARS = 6 };
+
+struct Serial_board
+{
+ enum Flags
+ {
+ F_bar_per_port = 0x10,
+ };
+
+ unsigned short flags;
+ unsigned short base_bar;
+ unsigned num_ports;
+ unsigned base_baud;
+ unsigned port_offset;
+ unsigned base_offset;
+ unsigned reg_shift;
+
+ Resource bars[NUM_BARS];
+
+ unsigned num_mem_bars() const
+ {
+ unsigned n = 0;
+ for (unsigned i = 0; i < NUM_BARS; ++i)
+ if (bars[i].type == Resource::MEM_BAR)
+ ++n;
+ return n;
+ }
+
+ unsigned num_io_bars() const
+ {
+ unsigned n = 0;
+ for (unsigned i = 0; i < NUM_BARS; ++i)
+ if (bars[i].type == Resource::IO_BAR)
+ ++n;
+ return n;
+ }
+
+ int first_io_bar()
+ {
+ for (unsigned i = 0; i < NUM_BARS; ++i)
+ if (bars[i].type == Resource::IO_BAR)
+ return i;
+ return -1;
+ }
+
+ l4_addr_t get_base(unsigned idx) const
+ {
+ if (idx >= num_ports)
+ idx = 0;
+
+ if (flags & F_bar_per_port)
+ return bars[base_bar + idx].base + base_offset;
+
+ return bars[base_bar].base + base_offset + port_offset * idx;
+ }
+
+ Resource::Type get_type() const
+ { return bars[base_bar].type; }
+};
+
+struct Pci_iterator
+{
+ unsigned bus;
+ unsigned dev;
+ unsigned func;
+
+ l4_uint32_t vd;
+
+ enum { Max_bus = 20 };
+
+ Pci_iterator() : bus(0), dev(0), func(0) {}
+ explicit Pci_iterator(unsigned bus, unsigned dev = 0, unsigned func = 0)
+ : bus(bus), dev(dev), func(func) {}
+
+ static Pci_iterator end() { return Pci_iterator(Max_bus, 0, 0); }
+
+ l4_uint32_t pci_read(l4_uint32_t reg, unsigned char width) const
+ { return ::pci_read(bus, dev, func, reg, width); }
+
+ void pci_write(l4_uint32_t reg, l4_uint32_t val, unsigned char width) const
+ { ::pci_write(bus, dev, func, reg, val, width); }
+
+ void enable_io() const
+ {
+ unsigned cmd = pci_read(4, 16);
+ pci_write(4, cmd | 1, 16);
+ }
+
+ void enable_mmio() const
+ {
+ unsigned cmd = pci_read(4, 16);
+ pci_write(4, cmd | 2, 16);
+ }
+
+ unsigned vendor() const { return vd & 0xffff; }
+ unsigned device() const { return vd >> 16; }
+ unsigned vendor_device() const { return vd; }
+
+ unsigned classcode() const { return pci_read(0x0b, 8); }
+ unsigned subclass() const { return pci_read(0x0a, 8); }
+ unsigned prog() const { return pci_read(9, 8); }
+
+ bool operator == (Pci_iterator const &o) const
+ { return bus == o.bus && dev == o.dev && func == o.func; }
+
+ bool operator != (Pci_iterator const &o) const
+ { return !operator == (o); }
+
+ Pci_iterator const &operator ++ ()
+ {
+ for (; bus < Max_bus;)
+ {
+ if (func == 0)
+ {
+ unsigned char hdr_type = pci_read(0xe, 8);
+ if (hdr_type & 0x80)
+ ++func;
+ else
+ ++dev;
+ }
+ else if (func < 8)
+ ++func;
+ else
+ {
+ func = 0;
+ ++dev;
+ }
+
+ if (dev >= 32)
+ {
+ ++bus;
+ dev = 0;
+ func = 0;
+ }
+
+ vd = pci_read(0, 32);
+ if (vd == 0xffffffff)
+ continue;
+
+ return *this;
+ }
+
+ dev = 0;
+ func = 0;
+ return *this;
+ }
+
+};
+
+#if 0
+ if (classcode == 0x06 && subclass == 0x04)
+ buses++;
+#endif
+
+
+
+struct Bs_uart : L4::Uart_16550
+{
+ union Regs
+ {
+ cxx::Static_container<L4::Io_register_block_port> io;
+ cxx::Static_container<L4::Io_register_block_mmio> mem;
+ };
+
+ Resource::Type type;
+ bool ok;
+ Regs uart_regs;
+
+ Bs_uart(Serial_board *board, unsigned port, unsigned long baudrate)
+ : L4::Uart_16550(board->base_baud, 0, 0, 0x8 /* out2 */, 0), ok(false)
+ {
+ type = board->get_type();
+ if (type == Resource::IO_BAR)
+ {
+ unsigned base = board->get_base(port);
+ uart_regs.io.construct(base);
+ if (!startup(uart_regs.io))
+ {
+ printf("Could not find or enable UART\n");
+ return;
+ }
+ }
+ if (type == Resource::MEM_BAR)
+ {
+ l4_addr_t base = board->get_base(port);
+ uart_regs.mem.construct(base, board->reg_shift);
+ if (!startup(uart_regs.mem))
+ {
+ printf("Could not find or enable UART\n");
+ return;
+ }
+ }
+
+ if (!change_mode(L4::Uart_16550::MODE_8N1, baudrate))
+ {
+ printf("Could not find or enable UART\n");
+ return;
+ }
+
+ ok = true;
+ }
+
+};
+
+class Dual_uart : public L4::Uart
+{
+private:
+ L4::Uart *_u1, *_u2;
+
+public:
+ Dual_uart(L4::Uart *u1)
+ : _u1(u1), _u2(0)
+ {}
+
+ void set_uart2(L4::Uart *u2)
+ {
+ _u2 = u2;
+ }
+
+ bool startup(L4::Io_register_block const *)
+ {
+ return true;
+ }
+
+ void shutdown()
+ {
+ _u1->shutdown();
+ if (_u2)
+ _u2->shutdown();
+ }
+
+ ~Dual_uart() {}
+#if 0
+ bool enable_rx_irq(bool e)
+ {
+ bool r1 = _u1->enable_rx_irq(e);
+ bool r2 = _u2 ? _u2->enable_rx_irq(e) : false;
+ return r1 && r2;
+ }
+
+ bool enable_tx_irq(bool e)
+ {
+ bool r1 = _u1->enable_tx_irq(e);
+ bool r2 = _u2 ? _u2->enable_tx_irq(e) : false;
+ return r1 && r2;
+ }
+#endif
+
+ bool change_mode(Transfer_mode m, Baud_rate r)
+ {
+ bool r1 = _u1->change_mode(m, r);
+ bool r2 = _u2 ? _u2->change_mode(m, r) : false;
+ return r1 && r2;
+ }
+
+ int char_avail() const
+ {
+ return _u1->char_avail() || (_u2 && _u2->char_avail());
+ }
+
+ int get_char(bool blocking) const
+ {
+ int c;
+ do
+ {
+ c = _u1->get_char(false);
+ if (c == -1 && _u2)
+ c = _u2->get_char(false);
+ }
+ while (blocking && c == -1);
+ return c;
+ }
+
+ int write(char const *s, unsigned long count) const
+ {
+ int r = _u1->write(s, count);
+ if (_u2)
+ _u2->write(s, count);
+ return r;
+ }
+
+};
+
+
+}
+
+struct Pci_com_drv
+{
+ virtual bool setup(Pci_iterator const &i, Serial_board *board) const = 0;
+ virtual ~Pci_com_drv() = 0;
+
+ static void read_bars(Pci_iterator const &i, Serial_board *board);
+
+};
+
+inline Pci_com_drv::~Pci_com_drv() {}
+
+void
+Pci_com_drv::read_bars(Pci_iterator const &dev, Serial_board *board)
+{
+ for (int bar = 0; bar < NUM_BARS; ++bar)
+ {
+ int a = 0x10 + bar * 4;
+
+ unsigned v = dev.pci_read(a, 32);
+ dev.pci_write(a, ~0U, 32);
+ unsigned x = dev.pci_read(a, 32);
+ dev.pci_write(a, v, 32);
+
+ if (!v)
+ continue;
+
+ int s;
+ for (s = 2; s < 32; ++s)
+ if ((x >> s) & 1)
+ break;
+
+ board->bars[bar].base = v & ~3UL;
+ board->bars[bar].len = 1 << s;
+ board->bars[bar].type = (v & 1) ? Resource::IO_BAR : Resource::MEM_BAR;
+
+ if (0)
+ printf("BAR%d: %04x (sz=%d)\n", bar, v & ~3, 1 << s);
+ }
+}
+
+
+struct Pci_com_drv_default : Pci_com_drv
+{
+ bool setup(Pci_iterator const &dev, Serial_board *board) const
+ {
+ read_bars(dev, board);
+ int num_iobars = board->num_io_bars();
+
+ if (num_iobars != 1)
+ return false;
+
+ //int num_membars = board->num_mem_bars();
+ //if (num_membars > 1)
+ // return false;
+
+ int first_port = board->first_io_bar();
+
+ board->port_offset = 8;
+ board->base_baud = L4::Uart_16550::Base_rate_x86;
+ board->base_bar = first_port;
+ board->num_ports = board->bars[first_port].len / board->port_offset;
+ board->flags = 0;
+ printf(" detected serial IO card: bar=%d ports=%d\n",
+ first_port, board->num_ports);
+ dev.enable_io();
+ return true;
+ }
+};
+
+struct Pci_com_drv_fallback : Pci_com_drv_default
+{
+ bool setup(Pci_iterator const &dev, Serial_board *board) const
+ {
+ // The default drivers only takes 7:80 typed devices
+ if (dev.classcode() != 7)
+ return false;
+
+ if (dev.subclass() != 0x80)
+ return false;
+
+ return Pci_com_drv_default::setup(dev, board);
+ }
+};
+
+
+
+
+struct Pci_com_drv_oxsemi : Pci_com_drv
+{
+ bool setup(Pci_iterator const &dev, Serial_board *board) const
+ {
+ read_bars(dev, board);
+ board->flags = 0;
+ board->num_ports = 0;
+
+ switch (dev.device())
+ {
+ case 0xc158:
+ board->num_ports = 2;
+ board->base_baud = 4000000;
+ board->port_offset = 0x200;
+ board->base_bar = 0;
+ board->base_offset = 0x1000;
+ board->reg_shift = 0;
+ break;
+ default:
+ break;
+ }
+
+ if (!board->num_ports)
+ return false;
+
+ printf(" found oxsemi PCI controller.\n");
+ dev.enable_mmio();
+ return true;
+ }
+};
+
+struct Pci_com_moschip : public Pci_com_drv
+{
+ bool setup(Pci_iterator const &dev, Serial_board *board) const
+ {
+ read_bars(dev, board);
+
+ int first_port = board->first_io_bar();
+
+ board->port_offset = 8;
+ board->base_baud = L4::Uart_16550::Base_rate_x86;
+ board->base_bar = first_port;
+ board->num_ports = board->bars[first_port].len / board->port_offset;
+ board->flags = 0;
+ printf(" detected serial IO card: bar=%d ports=%d\n",
+ first_port, board->num_ports);
+ dev.enable_io();
+ return true;
+ }
+
+};
+
+static Pci_com_drv_fallback _fallback_pci_com;
+static Pci_com_drv_default _default_pci_com;
+static Pci_com_drv_oxsemi _oxsemi_pci_com;
+static Pci_com_moschip _moschip;
+
+#define PCI_DEVICE_ID(vendor, device) \
+ (((unsigned)(device) << 16) | (unsigned)(vendor & 0xffff)), 0xffffffffU
+#define PCI_ANY_DEVICE 0, 0
+
+struct Pci_com_dev
+{
+ unsigned vendor_device;
+ unsigned mask;
+ Pci_com_drv *driver;
+};
+
+Pci_com_dev _devs[] = {
+ { PCI_DEVICE_ID(0x1415, 0xc158), &_oxsemi_pci_com },
+ { PCI_DEVICE_ID(0x9710, 0x9835), &_moschip },
+ { PCI_DEVICE_ID(0x9710, 0x9865), &_moschip },
+ { PCI_DEVICE_ID(0x9710, 0x9922), &_moschip },
+ { PCI_DEVICE_ID(0x8086, 0x8c3d), &_default_pci_com },
+ { PCI_ANY_DEVICE, &_fallback_pci_com },
+};
+
+enum { Num_known_devs = sizeof(_devs) / sizeof(_devs[0]) };
+
+
+static Pci_iterator
+_search_pci_serial_devs(Pci_iterator const &begin, Pci_iterator const &end,
+ Serial_board *board, bool print)
+{
+ for (Pci_iterator i = begin; i != end; ++i)
+ {
+ if (print)
+ printf("%02x:%02x.%1x Class %02x.%02x Prog %02x: %04x:%04x\n",
+ i.bus, i.dev, i.func, i.classcode(), i.subclass(), i.prog(),
+ i.vendor(), i.device());
+
+ for (unsigned devs = 0; devs < Num_known_devs; ++devs)
+ if ( (i.vendor_device() & _devs[devs].mask) == _devs[devs].vendor_device
+ && _devs[devs].driver->setup(i, board))
+ return i;
+ }
+
+ return end;
+}
+
+static unsigned long
+search_pci_serial_devs(int card_idx, Serial_board *board)
+{
+ Pci_iterator end = Pci_iterator::end();
+ Pci_iterator i;
+ for (int card = 0; i != end; ++i, ++card) {
+ i = _search_pci_serial_devs(i, end, board, false);
+ if (card == card_idx)
+ return 1;
+ }
+
+ return 0;
+}
+
+static void
+scan_pci_uarts(Dual_uart *du, unsigned long baudrate)
+{
+ Serial_board board;
+ Pci_iterator end = Pci_iterator::end();
+ // classes should be 7:0
+ Pci_iterator i;
+ for (int card = 0; i != end; ++i, ++card)
+ {
+ i = _search_pci_serial_devs(i, end, &board, true);
+
+ if (i == end)
+ break;
+
+ for (unsigned p = 0; p < board.num_ports; ++p)
+ {
+ printf("probed PCI UART %02x:%02x.%1x\n",
+ i.bus, i.dev, i.func);
+ Bs_uart u(&board, p, baudrate);
+ du->set_uart2(&u);
+ printf("probed PCI UART %02x:%02x.%1x\n"
+ "to use this port set: -comport=pci:%d:%d\n",
+ i.bus, i.dev, i.func, card, p);
+ du->set_uart2(0);
+ }
+ }
+ printf("done scanning PCI uarts\n");
+}
+
+class Uart_vga : public L4::Uart
+{
+public:
+ Uart_vga()
+ { }
+
+ bool startup(L4::Io_register_block const *)
+ {
+ vga_init();
+ return true;
+ }
+
+ ~Uart_vga() {}
+ void shutdown() {}
+ bool enable_rx_irq(bool) { return false; }
+ bool enable_tx_irq(bool) { return false; }
+ bool change_mode(Transfer_mode, Baud_rate) { return true; }
+ int get_char(bool blocking) const
+ {
+ int c;
+ do
+ c = raw_keyboard_getscancode();
+ while (blocking && c == -1);
+ return c;
+ }
+
+ int char_avail() const
+ {
+ return raw_keyboard_getscancode() != -1;
+ }
+
+ int write(char const *s, unsigned long count) const
+ {
+ unsigned long c = count;
+ while (c)
+ {
+ if (*s == 10)
+ vga_putchar(13);
+ vga_putchar(*s++);
+ --c;
+ }
+ return count;
+ }
+};
+
+
+static void
+legacy_uart(unsigned com_port_or_base, int &com_irq, Serial_board *board)
+{
+ switch (com_port_or_base)
+ {
+ case 1: com_port_or_base = 0x3f8;
+ if (com_irq == -1)
+ com_irq = 4;
+ break;
+ case 2: com_port_or_base = 0x2f8;
+ if (com_irq == -1)
+ com_irq = 3;
+ break;
+ case 3: com_port_or_base = 0x3e8; break;
+ case 4: com_port_or_base = 0x2e8; break;
+ }
+
+ board->num_ports = 1;
+ board->bars[0].type = Resource::IO_BAR;
+ board->bars[0].base = com_port_or_base;
+ board->base_bar = 0;
+ board->flags = 0;
+ board->base_offset = 0;
+ board->port_offset = 8;
+ board->base_baud = L4::Uart_16550::Base_rate_x86;
+ board->reg_shift = 0;
+}
+
+
+class Platform_x86 : public Platform_base
+{
+public:
+#ifdef ARCH_amd64
+ ptab64_mem_info_t const *ptab64_info;
+#endif
+ bool probe() { return true; }
+
+ int init_uart(Serial_board *board, int port, int com_irq, Dual_uart *du)
+ {
+ base_critical_enter();
+ unsigned baudrate = 115200;
+
+ static cxx::Static_container<Bs_uart> uart;
+ uart.construct(board, port, baudrate);
+
+ if (!uart->ok)
+ {
+ base_critical_leave();
+ return 1;
+ }
+
+ if (uart->type == Resource::IO_BAR)
+ {
+ unsigned base = board->get_base(port);
+ kuart.access_type = L4_kernel_options::Uart_type_ioport;
+ kuart.base_address = base;
+ printf("UART IO: @%x\n", base);
+ }
+ if (uart->type == Resource::MEM_BAR)
+ {
+ l4_addr_t base = board->get_base(port);
+ kuart.access_type = L4_kernel_options::Uart_type_mmio;
+ kuart.base_address = base;
+ printf("UART MMIO: @%p\n", (void*)base);
+ }
+
+ kuart.base_baud = board->base_baud;
+ kuart.baud = baudrate;
+ kuart.reg_shift = board->reg_shift;
+
+ du->set_uart2(uart);
+
+ kuart.irqno = com_irq;
+ kuart_flags |= L4_kernel_options::F_uart_base
+ | L4_kernel_options::F_uart_baud;
+ if (com_irq != -1)
+ kuart_flags |= L4_kernel_options::F_uart_irq;
+
+ base_critical_leave();
+ return 0;
+ }
+
+ void init()
+ {};
+
+ void setup_uart(char const *cmdline)
+ {
+ const char *s;
+ int comport = -1;
+ int comirq = -1;
+ int pci = 0;
+ static Uart_vga _vga;
+ static Dual_uart du(&_vga);
+ set_stdio_uart(&du);
+
+ if ((s = check_arg(cmdline, "-comirq")))
+ {
+ s += 8;
+ comirq = strtoul(s, 0, 0);
+ }
+
+ if ((s = check_arg(cmdline, "-comport")))
+ {
+ s += 9;
+ if ((pci = !strncmp(s, "pci:", 4)))
+ s += 4;
+
+ if (pci && !strncmp(s, "probe", 5))
+ {
+ scan_pci_uarts(&du, 115200);
+ reboot();
+ }
+
+ char *ep;
+ comport = strtoul(s, &ep, 0);
+ if (pci && *ep == ':')
+ {
+ pci = comport + 1;
+ comport = strtoul(ep + 1, 0, 0);
+ }
+ }
+
+ if (!check_arg(cmdline, "-noserial"))
+ {
+ Serial_board board;
+ if (pci)
+ {
+ if (!search_pci_serial_devs(pci - 1, &board))
+ {
+ legacy_uart(1, comirq, &board);
+ comport = 0;
+ }
+ }
+ else if (comport == -1)
+ {
+ legacy_uart(1, comirq, &board);
+ comport = 0;
+ }
+ else
+ {
+ legacy_uart(comport, comirq, &board);
+ comport = 0;
+ }
+
+ if (init_uart(&board, comport, comirq, &du))
+ {
+ kuart_flags |= L4_kernel_options::F_noserial;
+ printf("UART init failed\n");
+ }
+ }
+ else
+ kuart_flags |= L4_kernel_options::F_noserial;
+ }
+};
--- /dev/null
+/*!
+ * \file support_x86.cc
+ * \brief Support for the x86 platform
+ *
+ * \date 2008-01-02
+ * \author Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2008-2009 Author(s)
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include "support.h"
+#include "x86_pc-base.h"
+
+#include <string.h>
+#include "startup.h"
+#include "panic.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+enum { Verbose_mbi = 1 };
+
+namespace {
+
+#ifdef REALMODE_LOADING
+struct Platform_x86_1 : Platform_x86
+{
+ char const *realmode_pointer;
+
+ void setup_memory_map()
+ {
+ Region_list *ram = mem_manager->ram;
+ Region_list *regions = mem_manager->regions;
+
+ unsigned long m = *(l4_uint32_t*)(realmode_pointer + 0x1e0);
+ printf("Detected memory size: %ldKB\n", m);
+ ram->add(Region::n(0, 0x9fc00, ".ram", Region::Ram));
+ ram->add(Region::n(0x100000, (m + 1024) << 10, ".ram", Region::Ram));
+ regions->add(Region::n(0, 0x1000, ".BIOS", Region::Arch, 0));
+ // Quirks
+
+ // Fix EBDA in conventional memory
+ unsigned long p = *(l4_uint16_t *)0x40e << 4;
+
+ if (p > 0x400)
+ {
+ unsigned long e = p + 1024;
+ Region *r = ram->find(Region(p, e - 1));
+ if (r)
+ {
+ if (e - 1 < r->end())
+ ram->add(Region::n(e, r->end(), ".ram", Region::Ram), true);
+ r->end(p);
+ }
+ }
+ }
+
+ char const *cmdline() const
+ {
+ return 0;
+ l4_uint32_t p = *(l4_uint32_t*)(realmode_pointer + 0x228);
+ if (!p)
+ return 0;
+
+ return (char const *)p;
+ }
+};
+
+#else // REALMODE_LOADING
+
+struct Platform_x86_1 : Platform_x86
+{
+ l4util_mb_info_t *mbi;
+
+ void setup_memory_map()
+ {
+ Region_list *ram = mem_manager->ram;
+ Region_list *regions = mem_manager->regions;
+
+#ifdef ARCH_amd64
+ // add the page-table on which we're running in 64bit mode
+ regions->add(Region::n(ptab64_info->addr, ptab64_info->addr + ptab64_info->size,
+ ".bootstrap-ptab64", Region::Boot));
+#endif
+ if (!(mbi->flags & L4UTIL_MB_MEM_MAP))
+ {
+ assert(mbi->flags & L4UTIL_MB_MEMORY);
+ ram->add(Region::n(0, (mbi->mem_lower + 1024) << 10, ".ram",
+ Region::Ram));
+ ram->add(Region::n(0x100000, (mbi->mem_upper + 1024) << 10, ".ram",
+ Region::Ram));
+ }
+ else
+ {
+ l4util_mb_addr_range_t *mmap;
+ l4util_mb_for_each_mmap_entry(mmap, mbi)
+ {
+ unsigned long long start = (unsigned long long)mmap->addr;
+ unsigned long long end = (unsigned long long)mmap->addr + mmap->size;
+
+ switch (mmap->type)
+ {
+ case 1:
+ ram->add(Region::n(start, end, ".ram", Region::Ram));
+ break;
+ case 2:
+ case 3:
+ case 4:
+ regions->add(Region::n(start, end, ".BIOS", Region::Arch, mmap->type));
+ break;
+ case 5:
+ regions->add(Region::n(start, end, ".BIOS", Region::No_mem));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ regions->add(Region::n(0, 0x1000, ".BIOS", Region::Arch, 0));
+
+
+ // Quirks
+
+ // Fix EBDA in conventional memory
+ unsigned long p = *(l4_uint16_t *)0x40e << 4;
+
+ if (p > 0x400)
+ {
+ unsigned long e = p + 1024;
+ Region *r = ram->find(Region(p, e - 1));
+ if (r)
+ {
+ if (e - 1 < r->end())
+ ram->add(Region::n(e, r->end(), ".ram", Region::Ram), true);
+ r->end(p);
+ }
+ }
+ }
+};
+
+#endif // !REALMODE_LOADING
+
+
+#ifdef IMAGE_MODE
+
+class Platform_x86_loader_mbi :
+ public Platform_x86_1,
+ public Boot_modules_image_mode
+{
+public:
+ Boot_modules *modules() { return this; }
+
+};
+
+Platform_x86_loader_mbi _x86_pc_platform;
+
+#else // IMAGE_MODE
+
+class Platform_x86_multiboot : public Platform_x86_1, public Boot_modules
+{
+public:
+ Boot_modules *modules() { return this; }
+
+ Module module(unsigned index, bool) const
+ {
+ Module m;
+ l4util_mb_mod_t *mb_mod = (l4util_mb_mod_t*)(unsigned long)mbi->mods_addr;
+
+ m.start = (char const *)(l4_addr_t)mb_mod[index].mod_start;
+ m.end = (char const *)(l4_addr_t)mb_mod[index].mod_end;
+ m.cmdline = (char const *)(l4_addr_t)mb_mod[index].cmdline;
+ return m;
+ }
+
+ unsigned num_modules() const { return mbi->mods_count; }
+
+ void reserve()
+ {
+ Region_list *regions = mem_manager->regions;
+
+ regions->add(Region::n((unsigned long)mbi,
+ (unsigned long)mbi + sizeof(*mbi),
+ ".mbi", Region::Boot));
+
+ if (mbi->flags & L4UTIL_MB_CMDLINE)
+ regions->add(Region::n((unsigned long)mbi->cmdline,
+ (unsigned long)mbi->cmdline
+ + strlen((char const *)(l4_addr_t)mbi->cmdline) + 1,
+ ".mbi", Region::Boot));
+
+ l4util_mb_mod_t *mb_mod = (l4util_mb_mod_t*)(unsigned long)mbi->mods_addr;
+ regions->add(Region::n((unsigned long)mb_mod,
+ (unsigned long)&mb_mod[mbi->mods_count],
+ ".mbi", Region::Boot));
+
+ if (mbi->flags & L4UTIL_MB_VIDEO_INFO)
+ {
+ if (mbi->vbe_mode_info)
+ regions->add(Region::start_size(mbi->vbe_mode_info,
+ sizeof(l4util_mb_vbe_mode_t),
+ ".mbi", Region::Boot));
+ if (mbi->vbe_ctrl_info)
+ regions->add(Region::start_size(mbi->vbe_ctrl_info,
+ sizeof(l4util_mb_vbe_ctrl_t),
+ ".mbi", Region::Boot));
+ }
+
+
+ for (unsigned i = 0; i < mbi->mods_count; ++i)
+ regions->add(Region::n(mb_mod[i].cmdline,
+ (unsigned long)mb_mod[i].cmdline
+ + strlen((char const *)(l4_addr_t)mb_mod[i].cmdline) + 1,
+ ".mbi", Region::Boot));
+
+ for (unsigned i = 0; i < mbi->mods_count; ++i)
+ regions->add(mod_region(i, mb_mod[i].mod_start,
+ mb_mod[i].mod_end - mb_mod[i].mod_start));
+ }
+
+ void move_module(unsigned index, void *dest,
+ bool overlap_check)
+ {
+ l4util_mb_mod_t *mod = (l4util_mb_mod_t*)(unsigned long)mbi->mods_addr + index;
+ unsigned long size = mod->mod_end - mod->mod_start;
+ _move_module(index, dest, (char const *)(l4_addr_t)mod->mod_start,
+ size, overlap_check);
+
+ assert ((l4_addr_t)dest < 0xfffffff0);
+ assert ((l4_addr_t)dest < 0xfffffff0 - size);
+ mod->mod_start = (l4_addr_t)dest;
+ mod->mod_end = (l4_addr_t)dest + size;
+ }
+
+ l4util_mb_info_t *construct_mbi(unsigned long mod_addr)
+ {
+ // calculate the size needed to cover the full MBI, including command lines
+ unsigned long total_size = sizeof(l4util_mb_info_t);
+
+ // consider the global command line
+ if (mbi->flags & L4UTIL_MB_CMDLINE)
+ total_size += round_wordsize(strlen((char const *)(l4_addr_t)mbi->cmdline) + 1);
+
+ // consider VBE info
+ if (mbi->flags & L4UTIL_MB_VIDEO_INFO)
+ {
+ if (mbi->vbe_mode_info)
+ total_size += sizeof(l4util_mb_vbe_mode_t);
+
+ if (mbi->vbe_ctrl_info)
+ total_size += sizeof(l4util_mb_vbe_ctrl_t);
+ }
+
+ // consider modules
+ total_size += sizeof(l4util_mb_mod_t) * mbi->mods_count;
+
+ // scan through all modules and add the command line
+ l4util_mb_mod_t *mods = (l4util_mb_mod_t*)(unsigned long)mbi->mods_addr;
+ for (l4util_mb_mod_t *m = mods; m != mods + mbi->mods_count; ++m)
+ if (m->cmdline)
+ total_size += round_wordsize(strlen((char const *)(l4_addr_t)m->cmdline) + 1);
+
+ if (Verbose_mbi)
+ printf(" need %ld bytes to copy MBI\n", total_size);
+
+ // try to find a free region for the MBI
+ char *_mb = (char *)mem_manager->find_free_ram(total_size);
+ if (!_mb)
+ panic("fatal: could not allocate memory for multi-boot info\n");
+
+ // mark the region as reserved
+ mem_manager->regions->add(Region::start_size((l4_addr_t)_mb, total_size, ".mbi_rt",
+ Region::Root));
+ if (Verbose_mbi)
+ printf(" reserved %ld bytes at %p\n", total_size, _mb);
+
+ // copy the whole MBI
+ l4util_mb_info_t *dst = (l4util_mb_info_t *)_mb;
+ *dst = *mbi;
+
+ l4util_mb_mod_t *dst_mods = (l4util_mb_mod_t *)(dst + 1);
+ dst->mods_addr = (l4_addr_t)dst_mods;
+ _mb = (char *)(dst_mods + mbi->mods_count);
+
+ if (mbi->flags & L4UTIL_MB_VIDEO_INFO)
+ {
+ if (mbi->vbe_mode_info)
+ {
+ l4util_mb_vbe_mode_t *d = (l4util_mb_vbe_mode_t *)_mb;
+ *d = *((l4util_mb_vbe_mode_t *)(l4_addr_t)mbi->vbe_mode_info);
+ dst->vbe_mode_info = (l4_addr_t)d;
+ _mb = (char *)(d + 1);
+ }
+
+ if (mbi->vbe_ctrl_info)
+ {
+ l4util_mb_vbe_ctrl_t *d = (l4util_mb_vbe_ctrl_t *)_mb;
+ *d = *((l4util_mb_vbe_ctrl_t *)(l4_addr_t)mbi->vbe_ctrl_info);
+ dst->vbe_ctrl_info = (l4_addr_t)d;
+ _mb = (char *)(d + 1);
+ }
+ }
+
+ if (mbi->cmdline)
+ {
+ strcpy(_mb, (char const *)(l4_addr_t)mbi->cmdline);
+ dst->cmdline = (l4_addr_t)_mb;
+ _mb += round_wordsize(strlen(_mb) + 1);
+ }
+
+ for (unsigned i = 0; i < mbi->mods_count; ++i)
+ {
+ dst_mods[i] = mods[i];
+ if (char const *c = (char const *)(l4_addr_t)(mods[i].cmdline))
+ {
+ unsigned l = strlen(c) + 1;
+ dst_mods[i].cmdline = (l4_addr_t)_mb;
+ memcpy(_mb, c, l);
+ _mb += round_wordsize(l);
+ }
+ }
+
+ mbi = dst;
+
+ // remove the old MBI from the reserved memory
+ for (Region *r = mem_manager->regions->begin();
+ r != mem_manager->regions->end();)
+ {
+ if (strcmp(r->name(), ".mbi"))
+ ++r;
+ else
+ r = mem_manager->regions->remove(r);
+ }
+
+ move_modules(mod_addr);
+ return mbi;
+ }
+};
+
+Platform_x86_multiboot _x86_pc_platform;
+
+#endif // !IMAGE_MODE
+}
+
+extern "C"
+void __main(l4util_mb_info_t *mbi, unsigned long p2, char const *realmode_si,
+ ptab64_mem_info_t const *ptab64_info);
+
+void __main(l4util_mb_info_t *mbi, unsigned long p2, char const *realmode_si,
+ ptab64_mem_info_t const *ptab64_info)
+{
+ ctor_init();
+ Platform_base::platform = &_x86_pc_platform;
+ _x86_pc_platform.init();
+#ifdef ARCH_amd64
+ // remember this info to reserve the memory in setup_memory_map later
+ _x86_pc_platform.ptab64_info = ptab64_info;
+#else
+ (void)ptab64_info;
+#endif
+ char const *cmdline;
+#if defined(REALMODE_LOADING)
+ /* create synthetic multi boot info, if loaded from realmode */
+ (void)mbi;
+ (void)p2;
+ _x86_pc_platform.realmode_pointer = realmode_si;
+ cmdline = _x86_pc_platform.cmdline();
+ if (!cmdline)
+ cmdline = _mbi_cmdline;
+#else
+ (void)realmode_si;
+ assert(p2 == L4UTIL_MB_VALID); /* we need to be multiboot-booted */
+ _x86_pc_platform.mbi = mbi;
+ cmdline = (char const *)(l4_addr_t)mbi->cmdline;
+#endif
+ _x86_pc_platform.setup_uart(cmdline);
+
+ startup(cmdline);
+}
+
+
--- /dev/null
+/*!
+ * \file
+ * \brief Support for Zynq platforms
+ *
+ * \date 2013
+ * \author Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2013 Author(s)
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include "support.h"
+#include <l4/drivers/uart_cadence.h>
+
+namespace {
+class Platform_arm_zynq : public Platform_single_region_ram
+{
+ bool probe() { return true; }
+
+ void init()
+ {
+ static L4::Uart_cadence _uart;
+ unsigned long uart_addr;
+ switch (PLATFORM_UART_NR) {
+ case 0: uart_addr = 0xe0000000; // qemu
+ default:
+ case 1: uart_addr = 0xe0001000; // zedboard
+ };
+ static L4::Io_register_block_mmio r(uart_addr);
+ _uart.startup(&r);
+ _uart.change_mode(3, 115200);
+ set_stdio_uart(&_uart);
+ }
+
+ void reboot()
+ {
+ L4::Io_register_block_mmio r(0xf8000200);
+ r.write<unsigned>(1, 0);
+ }
+};
+}
+
+REGISTER_PLATFORM(Platform_arm_zynq);
--- /dev/null
+#include "support.h"
+#include <l4/cxx/minmax>
+#include <cassert>
+
+#ifdef RAM_SIZE_MB
+
+static unsigned long
+scan_ram_size(unsigned long base_addr, unsigned long max_scan_size_mb)
+{
+ // scan the RAM to find out the RAM size, note that at this point we have
+ // two regions in RAM that we cannot touch, &_start - &_end and the
+ // modules
+
+ // assume that the image is loaded correctly and we need to start
+ // probing for memory wraparounds beyond the end of our image
+ extern char _end[];
+#ifdef IMAGE_MODE
+ extern char _module_data_end[];
+ l4_addr_t lower_bound
+ = l4_round_size((l4_addr_t)cxx::max(_end, _module_data_end), 20);
+#else
+ l4_addr_t lower_bound = l4_round_size((l4_addr_t)_end, 20);
+#endif
+
+ assert(base_addr <= lower_bound);
+ lower_bound -= base_addr;
+
+ // must be a power of 2 and >= (1 << 20)
+ unsigned long increment;
+ unsigned long max_scan_size = max_scan_size_mb << 20;
+
+ // push the initial probe point beyond lower_bound
+ for (increment = 1 << 20;
+ increment < lower_bound && increment < max_scan_size;
+ increment *= 2)
+ {}
+
+ printf(" Scanning up to %ld MB RAM, starting at offset %ldMB\n",
+ max_scan_size_mb, increment >> 20);
+
+ // initialize memory probe points
+ for (unsigned long offset = increment;
+ offset < max_scan_size;
+ offset *= 2)
+ *(unsigned long *)(base_addr + offset) = 0;
+
+ // avoid gcc/clang optimization figuring out that base_addr might
+ // always be 0 and generating a trap here
+ asm("" : "+r" (base_addr));
+ // write something at offset 0, does it appear elsewhere?
+ *(unsigned long *)base_addr = 0x12345678;
+ asm volatile("" : : : "memory");
+ for (unsigned long offset = increment;
+ offset < max_scan_size;
+ offset *= 2)
+ if (*(unsigned long *)(base_addr + offset) == 0x12345678)
+ return offset >> 20; // detected a wrap around at offset
+
+ return max_scan_size_mb;
+}
+
+void
+Platform_single_region_ram::setup_memory_map()
+{
+ unsigned long ram_size_mb = scan_ram_size(RAM_BASE, RAM_SIZE_MB);
+ printf(" Memory size is %ldMB%s (%08lx - %08lx)\n",
+ ram_size_mb, ram_size_mb != RAM_SIZE_MB ? " (Limited by Scan)" : "",
+ (unsigned long)RAM_BASE, RAM_BASE + (ram_size_mb << 20) - 1);
+ mem_manager->ram->add(
+ Region::n(RAM_BASE,
+ (unsigned long long)RAM_BASE + (ram_size_mb << 20),
+ ".ram", Region::Ram));
+}
+#endif
--- /dev/null
+/*
+ * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ * Alexander Warg <warg@os.inf.tu-dresden.de>,
+ * Frank Mehnert <fm3@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "panic.h"
+#include <l4/util/l4_macros.h>
+
+#include "region.h"
+#include "module.h"
+
+unsigned long long
+Region_list::find_free(Region const &search, unsigned long long _size,
+ unsigned align) const
+{
+ unsigned long long start = search.begin();
+ unsigned long long end = search.end();
+ while (1)
+ {
+ start = (start + (1ULL << align) -1) & ~((1ULL << align)-1);
+
+ if (start + _size - 1 > end)
+ return 0;
+
+ if (0)
+ printf("try start %p\n", (void *)start);
+
+ Region *z = find(Region::start_size(start, _size));
+ if (!z)
+ return start;
+
+ start = z->end() + 1;
+ }
+}
+
+unsigned long long
+Region_list::find_free_rev(Region const &search, unsigned long long _size,
+ unsigned align) const
+{
+ unsigned long long start = search.begin();
+ unsigned long long end = search.end();
+ while (1)
+ {
+ end -= _size - 1;
+ end &= ~((1ULL << align)-1);
+
+ if (end < start)
+ return 0;
+
+ if (0)
+ printf("try start %p\n", (void *)end);
+
+ Region *z = find(Region::start_size(end, _size));
+ if (!z)
+ return end;
+
+ end = z->begin() - 1;
+ }
+}
+
+void
+Region_list::add_nolimitcheck(Region const ®ion, bool may_overlap)
+{
+ Region const *r;
+
+ /* Do not add empty regions */
+ if (region.begin() == region.end())
+ return;
+
+ if (_end >= _max)
+ {
+ // try to merge adjacent regions to gain space
+ optimize();
+
+ if (_end >= _max)
+ panic("Bootstrap: %s: Region overflow\n", __func__);
+ }
+
+ if (!may_overlap && (r = find(region)))
+ {
+ printf(" New region for list %s:\t", _name);
+ region.vprint();
+ printf(" overlaps with: \t");
+ r->vprint();
+
+ dump();
+ panic("region overlap");
+ }
+
+ *_end = region;
+ ++_end;
+ _combined_size += region.size();
+}
+
+void
+Region_list::add(Region const ®ion, bool may_overlap)
+{
+ Region mem = region;
+
+ if (mem.invalid())
+ {
+ printf(" WARNING: trying to add invalid region to %s list.\n", _name);
+ return;
+ }
+
+ if (mem.begin() > _address_limit)
+ {
+ printf(" Dropping '%s' region ", _name);
+ mem.print();
+ printf(" due to %lld MB address limit\n", _address_limit >> 20);
+ return;
+ }
+
+ if (mem.end() >= _address_limit)
+ {
+ printf(" Limiting '%s' region ", _name);
+ mem.print();
+ mem.end(_address_limit - 1);
+ printf(" to ");
+ mem.print();
+ printf(" due to %lld MB address limit\n", _address_limit >> 20);
+
+ }
+
+ if (_combined_size >= _max_combined_size)
+ {
+ printf(" Dropping '%s' region ", _name);
+ mem.print();
+ printf(" due to %lld MB size limit\n", _max_combined_size >> 20);
+ return;
+ }
+
+ if (_combined_size + mem.size() > _max_combined_size)
+ {
+ printf(" Limiting '%s' region ", _name);
+ mem.print();
+ mem.end(mem.begin() + _max_combined_size - _combined_size - 1);
+ printf(" to ");
+ mem.print();
+ printf(" due to %lld MB size limit\n", _max_combined_size >> 20);
+ }
+
+ add_nolimitcheck(mem, may_overlap);
+}
+
+Region *
+Region_list::find(Region const &o) const
+{
+ for (Region *c = _reg; c < _end; ++c)
+ if (c->overlaps(o))
+ return c;
+
+ return 0;
+}
+
+Region *
+Region_list::contains(Region const &o)
+{
+ for (Region *c = _reg; c < _end; ++c)
+ if (c->contains(o))
+ return c;
+
+ return 0;
+}
+
+void
+Region::print() const
+{
+ printf(" [%9llx, %9llx] {%9llx}", begin(), end(), size());
+}
+
+void
+Region::vprint() const
+{
+ static char const *types[] = {"Gap ", "Kern ", "Sigma0",
+ "Boot ", "Root ", "Arch ", "Ram ",
+ "Info " };
+ printf(" ");
+ print();
+ printf(" %s ", types[type()]);
+ if (name())
+ {
+ if (*name() == '.')
+ printf("%s", name() + 1);
+ else
+ print_module_name(name(), "");
+ }
+ putchar('\n');
+}
+
+void
+Region_list::dump()
+{
+ Region const *i;
+ Region const *j;
+ unsigned long long min, mark = 0;
+
+ printf("Regions of list '%s'\n", _name);
+ for (i = _reg; i < _end; ++i)
+ {
+ min = ~0;
+ Region const *min_idx = 0;
+ for (j = _reg; j < _end; ++j)
+ if (j->begin() < min && j->begin() >= mark)
+ {
+ min = j->begin();
+ min_idx = j;
+ }
+ if (!min_idx)
+ {
+ i->vprint();
+ continue;
+ }
+ min_idx->vprint();
+ mark = min_idx->begin() + 1;
+ }
+}
+
+void
+Region_list::swap(Region *a, Region *b)
+{
+ Region t = *a; *a = *b; *b = t;
+}
+
+void
+Region_list::sort()
+{
+ if (end() - begin() < 2)
+ return;
+ bool swapped;
+
+ Region *e = end() - 1;
+
+ do
+ {
+ swapped = false;
+ for (Region *c = begin(); c < e; ++c)
+ {
+ Region *n = c; ++n;
+ if (*n < *c)
+ {
+ swap(c,n);
+ swapped = true;
+ }
+ }
+ }
+ while (swapped);
+}
+
+Region *
+Region_list::remove(Region *r)
+{
+ memmove(r, r+1, (end() - r - 1)*sizeof(Region));
+ --_end;
+ return r;
+}
+
+void
+Region_list::optimize()
+{
+ sort();
+ Region *c = begin();
+ while (c < end())
+ {
+ Region *n = c; ++n;
+ if (n == end())
+ return;
+
+ if (n->type() == c->type() && n->sub_type() == c->sub_type()
+ && n->name() == c->name() &&
+ l4_round_page(c->end()) >= l4_trunc_page(n->begin()))
+ {
+ c->end(n->end());
+ remove(n);
+ }
+ else
+ ++c;
+ }
+}
+
+bool
+Region_list::sub(Region const &r)
+{
+ Region *c = contains(r);
+ if (!c)
+ return false;
+
+ if (c->begin() == r.begin() && c->end() == r.end())
+ {
+ remove(c);
+ return true;
+ }
+
+ if (c->begin() == r.begin())
+ {
+ c->begin(r.end() + 1);
+ return true;
+ }
+
+ if (c->end() == r.end())
+ {
+ c->end(r.begin() - 1);
+ return true;
+ }
+
+ Region tail(*c);
+ tail.begin(r.end() + 1);
+ c->end(r.begin() - 1);
+ add(tail);
+ return true;
+}
--- /dev/null
+/*
+ * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ * Alexander Warg <warg@os.inf.tu-dresden.de>,
+ * Frank Mehnert <fm3@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#ifndef REGION_H
+#define REGION_H
+
+#include <l4/sys/compiler.h>
+#include <l4/sys/l4int.h>
+
+#include "types.h"
+
+/** Region in memory. */
+class Region
+{
+public:
+ enum Type { No_mem, Kernel, Sigma0, Boot, Root, Arch, Ram, Info };
+
+ /** Basic noop constructor, to be able to have array without ini code */
+ Region() {}
+
+ /** Create an invalid region. */
+ Region(Type) : _begin(0), _end(0) {}
+
+ /** Create a 1byte region at begin, basically for lookups */
+ Region(unsigned long long begin)
+ : _begin(begin), _end(begin), _name(0), _t(No_mem), _s(0)
+ {}
+
+ /** Create a 1byte region for address \a ptr.
+ * @param ptr the start address for the 1byte region.
+ */
+ Region(void const *ptr)
+ : _begin((l4_addr_t)ptr), _end((l4_addr_t)ptr), _name(0), _t(No_mem), _s(0)
+ {}
+
+ /** Create a fully fledged region.
+ * @param begin The start address.
+ * @param end The address of the last byte in the region.
+ * @param name The name for the region (usually the binary name).
+ * @param t The type of the region.
+ * @param sub The subtype of the region.
+ */
+ Region(unsigned long long begin, unsigned long long end,
+ char const *name = 0, Type t = No_mem, short sub = 0)
+ : _begin(begin), _end(end), _name(name), _t(t), _s(sub)
+ {}
+
+ /**
+ * Create a region ...
+ * @param other a region to copy the name, the type, and the sub_type from
+ * @param begin the start address of the new region
+ * @param end the end address (inclusive) of the new region
+ */
+ Region(Region const &other, unsigned long long begin, unsigned long long end)
+ : _begin(begin), _end(end), _name(other._name), _t(other._t), _s(other._s)
+ {}
+
+ /**
+ * Create a region...
+ * @param begin The start address.
+ * @param end The address of the first byte after the region.
+ * @param name The name for the region (usually the binary name).
+ * @param t The type of the region.
+ * @param sub The subtype of the region.
+ */
+ static Region n(unsigned long long begin,
+ unsigned long long end, char const *name = 0,
+ Type t = No_mem, short sub = 0)
+ { return Region(begin, end - 1, name, t, sub); }
+
+ /**
+ * Create a region (using start and end pointers)
+ * @param begin start address
+ * @param end the address of the last byte in the region
+ * @param name The name of the region
+ * @param t the type of the region
+ * @param sub the subtype of the region
+ */
+ static Region n(void const *begin,
+ void const *end, char const *name = 0,
+ Type t = No_mem, short sub = 0)
+ { return Region((l4_addr_t)begin, (l4_addr_t)end - 1, name, t, sub); }
+
+ /**
+ * Create a region from start and size.
+ * @param begin the start address of the region
+ * @param size the size of the region in bytes
+ * @param name the name of the region
+ * @param t the type of the region
+ * @param sub the subtype of the region
+ */
+ static Region start_size(unsigned long long begin, unsigned long size,
+ char const *name = 0, Type t = No_mem,
+ short sub = 0)
+ { return Region(begin, begin + size - 1, name, t, sub); }
+
+ /**
+ * Create a region for the given object.
+ * @param begin a pointer to the object that shall be covered
+ * (the size of the region will be sizeof(T))
+ * @param name the name of the region
+ * @param t the type of theregion
+ * @param sub the subtype of the region
+ */
+ template< typename T >
+ static Region from_ptr(T const *begin, char const *name = 0,
+ Type t = No_mem, short sub = 0)
+ { return Region::start_size((l4_addr_t)begin, sizeof(T), name, t, sub); }
+
+ /**
+ * Create a region for an array of objects.
+ * @param begin pointer to the first element of the array
+ * @param size the number of elements in the array (the size of the
+ * whole region will be size * sizeof(T))
+ * @param name the name of the region
+ * @param t the type of the region
+ * @param sub the subtype of the region
+ */
+ template< typename T >
+ static Region array(T const *begin, unsigned long size, char const *name = 0,
+ Type t = No_mem, short sub = 0)
+ {
+ return Region::start_size((l4_addr_t)begin, sizeof(T) * size,
+ name, t, sub);
+ }
+
+ /** Get the start address. */
+ unsigned long long begin() const { return _begin; }
+ /** Get the address of the last byte. */
+ unsigned long long end() const { return _end; }
+ /** Set the start address. */
+ void begin(unsigned long long b) { _begin = b; }
+ /** Set the address of the last byte. */
+ void end(unsigned long long e) { _end = e; }
+ /** Get the name of the region. */
+ char const *name() const { return _name; }
+ /** Get size of the region */
+ unsigned long long size() const { return _end - _begin + 1; }
+ /** Set the name of the region. */
+ void name(char const *name) { _name = name; }
+ /** Get the type of the region. */
+ Type type() const { return (Type)(_t); }
+ /** Get the subtype of the region. */
+ short sub_type() const { return _s; }
+ /** Set the subtype of the region. */
+ void sub_type(short s) { _s = s; }
+
+ /** Print the region [begin; end] */
+ void print() const;
+
+ /** Print the region verbose (with name and type). */
+ void vprint() const;
+
+ /** Compare two regions. */
+ bool operator < (Region const &o) const
+ { return end() < o.begin(); }
+
+ /** Check for an overlap. */
+ bool overlaps(Region const &o) const
+ { return !(*this < o) && !(o < *this); }
+
+ /** Test if o is a sub-region of ourselves. */
+ bool contains(Region const &o) const
+ { return begin() <= o.begin() && end() >= o.end(); }
+
+ /** Calculate the intersection. */
+ Region intersect(Region const &o) const
+ {
+ if (!overlaps(o))
+ return Region(No_mem);
+
+ return Region(begin() > o.begin() ? begin() : o.begin(),
+ end() < o.end() ? end() : o.end(),
+ name(), type(), sub_type());
+ }
+
+ /** Check if the region is invalid */
+ bool invalid() const { return begin()==0 && end()==0; }
+
+private:
+ unsigned long long _begin, _end;
+ char const *_name;
+ short _t, _s;
+};
+
+
+/** List of memory regions, based on an fixed size array. */
+class Region_list
+{
+public:
+ /**
+ * Initialize the region list, using the array of given size
+ * as backing store.
+ */
+ void init(Region *store, unsigned size,
+ const char *name,
+ unsigned long long max_combined_size = ~0ULL,
+ unsigned long long address_limit = ~0ULL)
+ {
+ _reg = _end = store;
+ _max = _reg + size;
+ _name = name;
+ _max_combined_size = max_combined_size;
+ _address_limit = address_limit;
+ _combined_size = 0;
+ }
+
+ /** Helper template for array parameters
+ *
+ * This helper allows to access the type and the size of compile-time
+ * bound arrays. In particular used as parameters.
+ */
+ template< typename T >
+ struct Array_type_helper;
+
+ template< typename T, unsigned SZ >
+ struct Array_type_helper<T[SZ]> {
+ enum { size = SZ };
+ typedef T type;
+ };
+
+ /**
+ * Initialize the region list, using a region array as store
+ *
+ * @param store the array for the regoion backing store.
+ * @param name the name of the region list for output
+ * @param max_combined_size max sum of bytes in this list
+ * @param address_limit maximum allowed address in this list
+ */
+ template<typename STORE>
+ void init(STORE &store,
+ const char *name,
+ unsigned long long max_combined_size = ~0ULL,
+ unsigned long long address_limit = ~0ULL)
+ {
+ init(store, Array_type_helper<STORE>::size, name,
+ max_combined_size, address_limit);
+ }
+
+ /** Search for a region that overlaps o. */
+ Region *find(Region const &o) const;
+
+ /** Search for the region that contains o. */
+ Region *contains(Region const &o);
+
+ /**
+ * Search for a memory region not overlapping any known region,
+ * within search.
+ */
+ unsigned long long find_free(Region const &search,
+ unsigned long long size, unsigned align) const;
+
+ /**
+ * Search for a memory region not overlapping any know region, starting
+ * from the end of the search region.
+ */
+ unsigned long long find_free_rev(Region const &search, unsigned long long _size,
+ unsigned align) const;
+ /**
+ * Add a new region, with a upper limit check and verboseness.
+ */
+ void add(Region const &r, bool may_overlap = false);
+
+ bool sub(Region const &r);
+
+ /** Dump the whole region list. */
+ void dump();
+
+ /** Get the begin() iterator. */
+ Region *begin() const { return _reg; }
+ /** Get the end() iterator. */
+ Region *end() const { return _end; }
+
+ /** Remove the region given by the iterator r. */
+ Region *remove(Region *r);
+
+ /** Sort the region list (does bubble sort). */
+ void sort();
+
+ /** Optimize the region list.
+ * Basically merges all regions with the same type, subtype, and name
+ * that have a begin and end address on the same memory page.
+ */
+ void optimize();
+
+protected:
+ Region *_end;
+ Region *_max;
+ Region *_reg;
+
+ const char *_name;
+ unsigned long long _max_combined_size;
+ unsigned long long _address_limit;
+ unsigned long long _combined_size;
+
+private:
+ void swap(Region *a, Region *b);
+
+ /**
+ * Add a new memory region to the list. The new region must not overlap
+ * any known region.
+ */
+ void add_nolimitcheck(Region const &r, bool may_overlap = false);
+};
+
+#endif
--- /dev/null
+/**
+ * \file bootstrap/server/src/startup.cc
+ * \brief Main functions
+ *
+ * \date 09/2004
+ * \author Torsten Frenzel <frenzel@os.inf.tu-dresden.de>,
+ * Frank Mehnert <fm3@os.inf.tu-dresden.de>,
+ * Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ * Alexander Warg <aw11@os.inf.tu-dresden.de>
+ * Sebastian Sumpf <sumpf@os.inf.tu-dresden.de>
+ */
+
+/*
+ * (c) 2005-2009 Author(s)
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+/* LibC stuff */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+
+/* L4 stuff */
+#include <l4/sys/compiler.h>
+#include <l4/util/mb_info.h>
+#include <l4/util/l4_macros.h>
+#include <l4/util/kip.h>
+#include "panic.h"
+
+/* local stuff */
+#include "exec.h"
+#include "macros.h"
+#include "region.h"
+#include "module.h"
+#include "startup.h"
+#include "support.h"
+#include "init_kip.h"
+#include "patch.h"
+#include "koptions.h"
+
+#undef getchar
+
+/* management of allocated memory regions */
+static Region_list regions;
+static Region __regs[300];
+
+/* management of conventional memory regions */
+static Region_list ram;
+static Region __ram[16];
+
+static Memory _mem_manager = { &ram, ®ions };
+Memory *mem_manager = &_mem_manager;
+
+L4_kernel_options::Uart kuart;
+unsigned int kuart_flags;
+
+/*
+ * IMAGE_MODE means that all boot modules are linked together to one
+ * big binary.
+ */
+#ifdef IMAGE_MODE
+static l4_addr_t _mod_addr = RAM_BASE + MODADDR;
+#else
+static l4_addr_t _mod_addr;
+#endif
+
+static const char *builtin_cmdline = CMDLINE;
+
+
+enum {
+ kernel_module,
+ sigma0_module,
+ roottask_module,
+};
+
+/// Info passed through our ELF interpreter code
+struct Elf_info
+{
+ Boot_modules::Module mod;
+ Region::Type type;
+};
+
+static exec_handler_func_t l4_exec_read_exec;
+static exec_handler_func_t l4_exec_add_region;
+
+
+#if 0
+static void
+dump_mbi(l4util_mb_info_t *mbi)
+{
+ printf("%p-%p\n", (void*)(mbi->mem_lower << 10), (void*)(mbi->mem_upper << 10));
+ printf("MBI: [%p-%p]\n", mbi, mbi + 1);
+ printf("MODINFO: [%p-%p]\n", (char*)mbi->mods_addr,
+ (l4util_mb_mod_t*)(mbi->mods_addr) + mbi->mods_count);
+
+ printf("VBEINFO: [%p-%p]\n", (char*)mbi->vbe_ctrl_info,
+ (l4util_mb_vbe_ctrl_t*)(mbi->vbe_ctrl_info) + 1);
+ printf("VBEMODE: [%p-%p]\n", (char*)mbi->vbe_mode_info,
+ (l4util_mb_vbe_mode_t*)(mbi->vbe_mode_info) + 1);
+
+ l4util_mb_mod_t *m = (l4util_mb_mod_t*)(mbi->mods_addr);
+ l4util_mb_mod_t *me = m + mbi->mods_count;
+ for (; m < me; ++m)
+ {
+ printf(" MOD: [%p-%p]\n", (void*)m->mod_start, (void*)m->mod_end);
+ printf(" CMD: [%p-%p]\n", (char*)m->cmdline,
+ (char*)m->cmdline + strlen((char*)m->cmdline));
+ }
+}
+#endif
+
+
+/**
+ * Scan the memory regions with type == Region::Kernel for a
+ * kernel interface page (KIP).
+ *
+ * After loading the kernel we scan for the magic number at page boundaries.
+ */
+static
+void *find_kip()
+{
+ unsigned char *p, *end;
+ void *k = 0;
+
+ printf(" find kernel info page...\n");
+ for (Region const *m = regions.begin(); m != regions.end(); ++m)
+ {
+ if (m->type() != Region::Kernel)
+ continue;
+
+ if (sizeof(unsigned long) < 8
+ && m->end() >= (1ULL << 32))
+ end = (unsigned char *)(~0UL - 0x1000);
+ else
+ end = (unsigned char *) (unsigned long)m->end();
+
+ for (p = (unsigned char *) (unsigned long)(m->begin() & 0xfffff000);
+ p < end;
+ p += 0x1000)
+ {
+ l4_umword_t magic = L4_KERNEL_INFO_MAGIC;
+ if (memcmp(p, &magic, 4) == 0)
+ {
+ k = p;
+ printf(" found kernel info page at %p\n", p);
+ break;
+ }
+ }
+
+ if (k)
+ break;
+ }
+
+ if (!k)
+ panic("could not find kernel info page, maybe your kernel is too old");
+
+ return k;
+}
+
+static
+L4_kernel_options::Options *find_kopts(void *kip)
+{
+ unsigned long a = (unsigned long)kip + sizeof(l4_kernel_info_t);
+
+ // kernel-option directly follow the KIP page
+ a = (a + 4096 - 1) & ~0xfff;
+
+ L4_kernel_options::Options *ko = (L4_kernel_options::Options *)a;
+
+ if (ko->magic != L4_kernel_options::Magic)
+ panic("Could not find kernel options page");
+
+ unsigned long need_version = 1;
+
+ if (ko->version != need_version)
+ panic("Cannot boot kernel with incompatible options version: %lu, need %lu",
+ (unsigned long)ko->version, need_version);
+
+ return ko;
+}
+
+/**
+ * Get the API version from the KIP.
+ */
+static inline
+unsigned long get_api_version(void *kip)
+{
+ return ((unsigned long *)kip)[1];
+}
+
+
+static char const *
+check_arg_str(char const *cmdline, const char *arg)
+{
+ char const *s = cmdline;
+ while ((s = strstr(s, arg)))
+ {
+ if (s == cmdline
+ || isspace(s[-1]))
+ return s;
+ }
+ return NULL;
+}
+
+static char *
+check_arg_str(char *cmdline, const char *arg)
+{
+ return const_cast<char *>(check_arg_str(const_cast<char const *>(cmdline), arg));
+}
+
+/**
+ * Scan the command line for the given argument.
+ *
+ * The cmdline string may either be including the calling program
+ * (.../bootstrap -arg1 -arg2) or without (-arg1 -arg2) in the realmode
+ * case, there, we do not have a leading space
+ *
+ * return pointer after argument, NULL if not found
+ */
+char const *
+check_arg(char const *cmdline, const char *arg)
+{
+ if (cmdline)
+ return check_arg_str(cmdline, arg);
+
+ return NULL;
+}
+
+
+/**
+ * Calculate the maximum memory limit in MB.
+ *
+ * The limit is the highest physical address where conventional RAM is allowed.
+ * The memory is limited to 3 GB IA32 and unlimited on other systems.
+ */
+static
+unsigned long long
+get_memory_max_address()
+{
+#ifndef __LP64__
+ /* Limit memory, we cannot really handle more right now. In fact, the
+ * problem is roottask. It maps as many superpages/pages as it gets.
+ * After that, the remaining pages are mapped using l4sigma0_map_anypage()
+ * with a receive window of L4_WHOLE_ADDRESS_SPACE. In response Sigma0
+ * could deliver pages beyond the 3GB user space limit. */
+ return 3024ULL << 20;
+#endif
+
+ return ~0ULL;
+}
+
+/*
+ * If available the '-maxmem=xx' command line option is used.
+ */
+static
+unsigned long long
+get_memory_max_size(char const *cmdline)
+{
+ /* maxmem= parameter? */
+ if (char const *c = check_arg(cmdline, "-maxmem="))
+ return strtoul(c + 8, NULL, 10) << 20;
+
+ return ~0ULL;
+}
+
+static int
+parse_memvalue(const char *s, unsigned long *val, char **ep)
+{
+
+ *val = strtoul(s, ep, 0);
+ if (*val == ~0UL)
+ return 1;
+
+ switch (**ep)
+ {
+ case 'G': *val <<= 10;
+ case 'M': *val <<= 10;
+ case 'k': case 'K': *val <<= 10; (*ep)++;
+ };
+
+ return 0;
+}
+
+/*
+ * Parse a memory layout string: size@offset
+ * E.g.: 256M@0x40000000, or 128M@128M
+ */
+static int
+parse_mem_layout(const char *s, unsigned long *sz, unsigned long *offset)
+{
+ char *ep;
+
+ if (parse_memvalue(s, sz, &ep))
+ return 1;
+
+ if (*sz == 0)
+ return 1;
+
+ if (*ep != '@')
+ return 1;
+
+ if (parse_memvalue(ep + 1, offset, &ep))
+ return 1;
+
+ return 0;
+}
+
+static void
+dump_ram_map(bool show_total = false)
+{
+ // print RAM summary
+ unsigned long long sum = 0;
+ for (Region *i = ram.begin(); i < ram.end(); ++i)
+ {
+ printf(" RAM: %016llx - %016llx: %lldkB\n",
+ i->begin(), i->end(), i->size() >> 10);
+ sum += i->size();
+ }
+ if (show_total)
+ printf(" Total RAM: %lldMB\n", sum >> 20);
+}
+
+static void
+setup_memory_map(char const *cmdline)
+{
+ bool parsed_mem_option = false;
+ const char *s = cmdline;
+
+ if (s)
+ {
+ while ((s = check_arg_str((char *)s, "-mem=")))
+ {
+ s += 5;
+ unsigned long sz, offset = 0;
+ if (!parse_mem_layout(s, &sz, &offset))
+ {
+ parsed_mem_option = true;
+ ram.add(Region::n(offset, offset + sz, ".ram", Region::Ram));
+ }
+ }
+ }
+
+ if (!parsed_mem_option)
+ // No -mem option given, use the one given by the platform
+ Platform_base::platform->setup_memory_map();
+
+ dump_ram_map(true);
+}
+
+static void do_the_memset(unsigned long s, unsigned val, unsigned long len)
+{
+ printf("Presetting memory %16lx - %16lx to '%x'\n",
+ s, s + len - 1, val);
+ memset((void *)s, val, len);
+}
+
+static void fill_mem(unsigned fill_value)
+{
+ regions.sort();
+ for (Region const *r = ram.begin(); r != ram.end(); ++r)
+ {
+ unsigned long long b = r->begin();
+ // The regions list must be sorted!
+ for (Region const *reg = regions.begin(); reg != regions.end(); ++reg)
+ {
+ // completely before ram?
+ if (reg->end() < r->begin())
+ continue;
+ // completely after ram?
+ if (reg->begin() > r->end())
+ break;
+
+ if (reg->begin() <= r->begin())
+ b = reg->end() + 1;
+ else if (b > reg->begin()) // some overlapping
+ {
+ if (reg->end() + 1 > b)
+ b = reg->end() + 1;
+ }
+ else
+ {
+ do_the_memset(b, fill_value, reg->begin() - 1 - b + 1);
+ b = reg->end() + 1;
+ }
+ }
+
+ if (b < r->end())
+ do_the_memset(b, fill_value, r->end() - b + 1);
+ }
+}
+
+
+/**
+ * Add the bootstrap binary itself to the allocated memory regions.
+ */
+static void
+init_regions()
+{
+ extern int _start; /* begin of image -- defined in crt0.S */
+ extern int _end; /* end of image -- defined by bootstrap.ld */
+
+ auto *p = Platform_base::platform;
+
+ regions.add(Region::n(p->to_phys((unsigned long)&_start),
+ p->to_phys((unsigned long)&_end),
+ ".bootstrap", Region::Boot));
+}
+
+/**
+ * Add all sections of the given ELF binary to the allocated regions.
+ * Actually does not load the ELF binary (see load_elf_module()).
+ */
+static void
+add_elf_regions(Boot_modules::Module const &m, Region::Type type)
+{
+ Elf_info info;
+ l4_addr_t entry;
+ int r;
+ const char *error_msg;
+
+ info.type = type;
+ info.mod = m;
+
+ printf(" Scanning %s\n", m.cmdline);
+
+ r = exec_load_elf(l4_exec_add_region, &info,
+ &error_msg, &entry);
+
+ if (r)
+ {
+ if (Verbose_load)
+ {
+ printf("\n%p: ", (void*)m.start);
+ for (int i = 0; i < 4; ++i)
+ printf("%08x ", *((unsigned *)m.start + i));
+ printf(" ");
+ for (int i = 0; i < 16; ++i)
+ {
+ unsigned char c = *(unsigned char *)((char *)m.start + i);
+ printf("%c", c < 32 ? '.' : c);
+ }
+ }
+ panic("\n\nThis is an invalid binary, fix it (%s).", error_msg);
+ }
+}
+
+
+/**
+ * Load the given ELF binary into memory and free the source
+ * memory region.
+ */
+static l4_addr_t
+load_elf_module(Boot_modules::Module const &mod)
+{
+ l4_addr_t entry;
+ int r;
+ const char *error_msg;
+
+ r = exec_load_elf(l4_exec_read_exec, const_cast<Boot_modules::Module *>(&mod),
+ &error_msg, &entry);
+
+#ifndef RELEASE_MODE
+ /* clear the image for debugging and security reasons */
+ memset((void*)mod.start, 0, mod.end - mod.start);
+#endif
+
+ if (r)
+ printf(" => can't load module (%s)\n", error_msg);
+ else
+ {
+ Region m = Region::n(mod.start, l4_round_page(mod.end));
+ if (!regions.sub(m))
+ {
+ Region m = Region::n(mod.start, mod.end);
+ if (!regions.sub(m))
+ {
+ m.vprint();
+ regions.dump();
+ panic ("could not free region for load ELF module");
+ }
+ }
+ }
+
+ return entry;
+}
+
+/**
+ * Simple linear memory allocator.
+ *
+ * Allocate size bytes starting from *ptr and set *ptr to *ptr + size.
+ */
+static inline void*
+lin_alloc(l4_size_t size, char **ptr)
+{
+ void *ret = *ptr;
+ *ptr += (size + 3) & ~3;;
+ return ret;
+}
+
+
+#ifdef ARCH_arm
+static inline l4_umword_t
+running_in_hyp_mode()
+{
+ l4_umword_t cpsr;
+ asm volatile("mrs %0, cpsr" : "=r"(cpsr));
+ return (cpsr & 0x1f) == 0x1a;
+}
+
+static void
+setup_and_check_kernel_config(Platform_base *plat, l4_kernel_info_t *kip)
+{
+ l4_kip_platform_info_arch *ia = &kip->platform_info.arch;
+
+ asm("mrc p15, 0, %0, c0, c0, 0" : "=r" (ia->cpuinfo.MIDR));
+ asm("mrc p15, 0, %0, c0, c0, 1" : "=r" (ia->cpuinfo.CTR));
+ asm("mrc p15, 0, %0, c0, c0, 2" : "=r" (ia->cpuinfo.TCMTR));
+ asm("mrc p15, 0, %0, c0, c0, 3" : "=r" (ia->cpuinfo.TLBTR));
+ asm("mrc p15, 0, %0, c0, c0, 5" : "=r" (ia->cpuinfo.MPIDR));
+ asm("mrc p15, 0, %0, c0, c0, 6" : "=r" (ia->cpuinfo.REVIDR));
+
+ if (((ia->cpuinfo.MIDR >> 16) & 0xf) >= 7)
+ {
+ asm("mrc p15, 0, %0, c0, c1, 0" : "=r" (ia->cpuinfo.ID_PFR[0]));
+ asm("mrc p15, 0, %0, c0, c1, 1" : "=r" (ia->cpuinfo.ID_PFR[1]));
+ asm("mrc p15, 0, %0, c0, c1, 2" : "=r" (ia->cpuinfo.ID_DFR0));
+ asm("mrc p15, 0, %0, c0, c1, 3" : "=r" (ia->cpuinfo.ID_AFR0));
+ asm("mrc p15, 0, %0, c0, c1, 4" : "=r" (ia->cpuinfo.ID_MMFR[0]));
+ asm("mrc p15, 0, %0, c0, c1, 5" : "=r" (ia->cpuinfo.ID_MMFR[1]));
+ asm("mrc p15, 0, %0, c0, c1, 6" : "=r" (ia->cpuinfo.ID_MMFR[2]));
+ asm("mrc p15, 0, %0, c0, c1, 7" : "=r" (ia->cpuinfo.ID_MMFR[3]));
+ asm("mrc p15, 0, %0, c0, c2, 0" : "=r" (ia->cpuinfo.ID_ISAR[0]));
+ asm("mrc p15, 0, %0, c0, c2, 1" : "=r" (ia->cpuinfo.ID_ISAR[1]));
+ asm("mrc p15, 0, %0, c0, c2, 2" : "=r" (ia->cpuinfo.ID_ISAR[2]));
+ asm("mrc p15, 0, %0, c0, c2, 3" : "=r" (ia->cpuinfo.ID_ISAR[3]));
+ asm("mrc p15, 0, %0, c0, c2, 4" : "=r" (ia->cpuinfo.ID_ISAR[4]));
+ asm("mrc p15, 0, %0, c0, c2, 5" : "=r" (ia->cpuinfo.ID_ISAR[5]));
+ }
+
+ const char *s = l4_kip_version_string(kip);
+ if (!s)
+ return;
+
+ bool is_hyp_kernel = false;
+ l4util_kip_for_each_feature(s)
+ if (!strcmp(s, "arm:hyp"))
+ {
+ if (!running_in_hyp_mode())
+ {
+ printf(" Detected HYP kernel, switching to HYP mode\n");
+ plat->arm_switch_to_hyp();
+ if (!running_in_hyp_mode())
+ panic("\nFailed to switch to HYP as required by Fiasco.OC.\n");
+ }
+ is_hyp_kernel = true;
+ break;
+ }
+
+ if (!is_hyp_kernel && running_in_hyp_mode())
+ {
+ printf(" Non-HYP kernel detected but running in HYP mode, switching back.\n");
+ asm volatile("mcr p15, 0, sp, c13, c0, 2 \n"
+ "msr spsr, %0 \n"
+ "adr r0, 1f \n"
+ ".inst 0xe12ef300 \n" // msr elr_hyp, r0
+ ".inst 0xe160006e \n" // eret
+ "1: mrc p15, 0, sp, c13, c0, 2 \n"
+ : : "r" (0x1d3) : "r0", "memory");
+ }
+}
+#endif /* arm */
+
+static unsigned long
+load_elf_module(Boot_modules::Module const &mod, char const *n)
+{
+ printf(" Loading "); print_module_name(mod.cmdline, n); putchar('\n');
+ return load_elf_module(mod);
+}
+
+/**
+ * \brief Startup, started from crt0.S
+ */
+/* entry point */
+void
+startup(char const *cmdline)
+{
+ if (!cmdline || !*cmdline)
+ cmdline = builtin_cmdline;
+
+ if (check_arg(cmdline, "-noserial"))
+ set_stdio_uart(NULL);
+
+ if (!Platform_base::platform)
+ {
+ // will we ever see this?
+ printf("No platform found, hangup.");
+ while (1)
+ ;
+ }
+
+ Platform_base *plat = Platform_base::platform;
+
+ if (check_arg(cmdline, "-wait"))
+ {
+ puts("\nL4 Bootstrapper is waiting for key input to continue...");
+ if (getchar() == -1)
+ puts(" ...no key input available.");
+ else
+ puts(" ...going on.");
+ }
+
+ puts("\nL4 Bootstrapper");
+ puts(" Build: #" BUILD_NR " " BUILD_DATE
+#ifdef ARCH_x86
+ ", x86-32"
+#endif
+#ifdef ARCH_amd64
+ ", x86-64"
+#endif
+#ifdef __VERSION__
+ ", " __VERSION__
+#endif
+ );
+
+ regions.init(__regs, "regions");
+ ram.init(__ram, "RAM", get_memory_max_size(cmdline), get_memory_max_address());
+
+ setup_memory_map(cmdline);
+
+ /* basically add the bootstrap binary to the allocated regions */
+ init_regions();
+ plat->modules()->reserve();
+
+ /* modules to load by bootstrap */
+ bool sigma0 = true; /* we need sigma0 */
+ bool roottask = true; /* we need a roottask */
+
+ /* check command line */
+ if (check_arg(cmdline, "-no-sigma0"))
+ sigma0 = 0;
+
+ if (check_arg(cmdline, "-no-roottask"))
+ roottask = 0;
+
+ if (const char *s = check_arg(cmdline, "-modaddr"))
+ _mod_addr = RAM_BASE + strtoul(s + 9, 0, 0);
+
+ _mod_addr = l4_round_page(_mod_addr);
+
+
+ Boot_modules *mods = plat->modules();
+
+ add_elf_regions(mods->module(kernel_module), Region::Kernel);
+
+ if (sigma0)
+ add_elf_regions(mods->module(sigma0_module), Region::Sigma0);
+
+ if (roottask)
+ add_elf_regions(mods->module(roottask_module), Region::Root);
+
+ l4util_mb_info_t *mbi = plat->modules()->construct_mbi(_mod_addr);
+
+ /* We need at least two boot modules */
+ assert(mbi->flags & L4UTIL_MB_MODS);
+ /* We have at least the L4 kernel and the first user task */
+ assert(mbi->mods_count >= 2);
+ assert(mbi->mods_count <= MODS_MAX);
+
+ if (const char *s = cmdline)
+ {
+ /* patch modules with content given at command line */
+ while ((s = check_arg_str((char *)s, "-patch=")))
+ patch_module(&s, mbi);
+ }
+
+ boot_info_t boot_info;
+ l4util_mb_mod_t *mb_mod = (l4util_mb_mod_t *)(unsigned long)mbi->mods_addr;
+ regions.optimize();
+
+ /* setup kernel PART ONE */
+ boot_info.kernel_start = load_elf_module(mods->module(kernel_module), "[KERNEL]");
+
+ /* setup sigma0 */
+ if (sigma0)
+ boot_info.sigma0_start = load_elf_module(mods->module(sigma0_module), "[SIGMA0]");
+
+ /* setup roottask */
+ if (roottask)
+ boot_info.roottask_start = load_elf_module(mods->module(roottask_module),
+ "[ROOTTASK]");
+
+ /* setup kernel PART TWO (special kernel initialization) */
+ void *l4i = find_kip();
+
+ regions.optimize();
+ regions.dump();
+
+ if (char const *c = check_arg(cmdline, "-presetmem="))
+ {
+ unsigned fill_value = strtoul(c + 11, NULL, 0);
+ fill_mem(fill_value);
+ }
+
+ L4_kernel_options::Options *lko = find_kopts(l4i);
+ kcmdline_parse(L4_CONST_CHAR_PTR(mb_mod[kernel_module].cmdline), lko);
+ lko->uart = kuart;
+ lko->flags |= kuart_flags;
+
+
+ /* setup the L4 kernel info page before booting the L4 microkernel:
+ * patch ourselves into the booter task addresses */
+ unsigned long api_version = get_api_version(l4i);
+ unsigned major = api_version >> 24;
+ printf(" API Version: (%x) %s\n", major, (major & 0x80)?"experimental":"");
+ switch (major)
+ {
+ case 0x87: // Fiasco
+ init_kip_f(l4i, &boot_info, mbi, &ram, ®ions);
+ break;
+ case 0x02:
+ panic("cannot boot V.2 API kernels: %lx\n", api_version);
+ break;
+ case 0x03:
+ panic("cannot boot X.0 and X.1 API kernels: %lx\n", api_version);
+ break;
+ case 0x84:
+ panic("cannot boot Fiasco V.4 API kernels: %lx\n", api_version);
+ break;
+ case 0x04:
+ panic("cannot boot V.4 API kernels: %lx\n", api_version);
+ default:
+ panic("cannot boot a kernel with unknown api version %lx\n", api_version);
+ break;
+ }
+
+ printf(" Starting kernel ");
+ print_module_name(L4_CONST_CHAR_PTR(mb_mod[kernel_module].cmdline),
+ "[KERNEL]");
+ printf(" at " l4_addr_fmt "\n", boot_info.kernel_start);
+
+#if defined(ARCH_arm)
+ if (major == 0x87)
+ setup_and_check_kernel_config(plat, (l4_kernel_info_t *)l4i);
+#endif
+#if defined(ARCH_ppc32)
+ init_kip_v2_arch((l4_kernel_info_t*)l4i);
+
+ printf("CPU at %lu Khz/Bus at %lu Hz\n",
+ ((l4_kernel_info_t*)l4i)->frequency_cpu,
+ ((l4_kernel_info_t*)l4i)->frequency_bus);
+#endif
+
+ plat->boot_kernel(boot_info.kernel_start);
+ /*NORETURN*/
+}
+
+static int
+l4_exec_read_exec(void * handle,
+ l4_addr_t file_ofs, l4_size_t file_size,
+ l4_addr_t mem_addr, l4_addr_t /*v_addr*/,
+ l4_size_t mem_size,
+ exec_sectype_t section_type)
+{
+ Boot_modules::Module const *m = (Boot_modules::Module const *)handle;
+ if (!mem_size)
+ return 0;
+
+ if (! (section_type & EXEC_SECTYPE_ALLOC))
+ return 0;
+
+ if (! (section_type & (EXEC_SECTYPE_ALLOC|EXEC_SECTYPE_LOAD)))
+ return 0;
+
+ if (Verbose_load)
+ printf(" [%p-%p]\n", (void *) mem_addr, (void *) (mem_addr + mem_size));
+
+ if (!ram.contains(Region::n(mem_addr, mem_addr + mem_size)))
+ {
+ printf("To be loaded binary region is out of memory region.\n");
+ printf(" Binary region: %lx - %lx\n", mem_addr, mem_addr + mem_size);
+ dump_ram_map();
+ panic("Binary outside memory");
+ }
+
+ memcpy((void *) mem_addr, (char const *)m->start + file_ofs, file_size);
+ if (file_size < mem_size)
+ memset((void *) (mem_addr + file_size), 0, mem_size - file_size);
+
+
+ Region *f = regions.find(mem_addr);
+ if (!f)
+ {
+ printf("could not find %lx\n", mem_addr);
+ regions.dump();
+ panic("Oops: region for module not found\n");
+ }
+
+ f->name(m->cmdline ? m->cmdline : ".[Unknown]");
+ return 0;
+}
+
+
+static int
+l4_exec_add_region(void *handle,
+ l4_addr_t /*file_ofs*/, l4_size_t /*file_size*/,
+ l4_addr_t mem_addr, l4_addr_t v_addr,
+ l4_size_t mem_size,
+ exec_sectype_t section_type)
+{
+ Elf_info const *info = (Elf_info const *)handle;
+
+ if (!mem_size)
+ return 0;
+
+ if (! (section_type & EXEC_SECTYPE_ALLOC))
+ return 0;
+
+ if (! (section_type & (EXEC_SECTYPE_ALLOC|EXEC_SECTYPE_LOAD)))
+ return 0;
+
+ Region n = Region::n(mem_addr, mem_addr + mem_size,
+ info->mod.cmdline ? info->mod.cmdline : ".[Unknown]",
+ info->type, mem_addr == v_addr ? 1 : 0);
+
+ for (Region *r = regions.begin(); r != regions.end(); ++r)
+ if (r->overlaps(n) && r->name() != Boot_modules::Mod_reg)
+ {
+ printf(" New region for list %s:\t", n.name());
+ n.vprint();
+ printf(" overlaps with: \t");
+ r->vprint();
+ regions.dump();
+ panic("region overlap");
+ }
+
+ regions.add(Region::n(mem_addr, mem_addr + mem_size,
+ info->mod.cmdline ? info->mod.cmdline : ".[Unknown]",
+ info->type, mem_addr == v_addr ? 1 : 0), true);
+ return 0;
+}
--- /dev/null
+/*
+ * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ * Alexander Warg <warg@os.inf.tu-dresden.de>,
+ * Frank Mehnert <fm3@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#ifndef __STARTUP_H__
+#define __STARTUP_H__
+
+#include <l4/sys/l4int.h>
+#include <l4/util/mb_info.h>
+#include <l4/sys/compiler.h>
+
+#include "types.h"
+
+typedef struct
+{
+ unsigned long kernel_start;
+ unsigned long sigma0_start;
+ unsigned long roottask_start;
+ unsigned long mbi_low, mbi_high;
+} boot_info_t;
+
+//const char * get_cmdline(l4util_mb_info_t *mbi);
+
+#ifdef __cplusplus
+#include "koptions-def.h"
+char const *check_arg(char const *cmdline, const char *arg);
+extern L4_kernel_options::Uart kuart;
+extern unsigned int kuart_flags;
+extern "C" void startup(char const *cmdline);
+#else
+extern void startup(char const *cmdline);
+#endif
+
+#endif /* ! __STARTUP_H__ */
--- /dev/null
+/*!
+ * \file support.h
+ * \brief Support header file
+ *
+ * \date 2008-01-02
+ * \author Adam Lackorznynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2008-2009 Author(s)
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#ifndef __BOOTSTRAP__SUPPORT_H__
+#define __BOOTSTRAP__SUPPORT_H__
+
+#include <l4/drivers/uart_base.h>
+#include <l4/util/mb_info.h>
+#include <stdio.h>
+#include "region.h"
+#include <cstring>
+#include <cstdlib>
+
+L4::Uart *uart();
+void set_stdio_uart(L4::Uart *uart);
+void ctor_init();
+
+// only available with image builds
+extern char _mbi_cmdline[];
+
+enum { Verbose_load = 0 };
+
+template<typename T>
+inline T *l4_round_page(T *p) { return (T*)l4_round_page((l4_addr_t)p); }
+
+template<typename T>
+inline T *l4_trunc_page(T *p) { return (T*)l4_trunc_page((l4_addr_t)p); }
+
+static inline void __attribute__((always_inline))
+clear_bss()
+{
+ extern char _bss_start[], _bss_end[];
+ extern char crt0_stack_low[], crt0_stack_high[];
+ memset(_bss_start, 0, (char *)&crt0_stack_low - _bss_start);
+ memset(crt0_stack_high, 0, _bss_end - crt0_stack_high);
+}
+
+static inline unsigned long
+round_wordsize(unsigned long s)
+{ return (s + sizeof(unsigned long) - 1) & ~(sizeof(unsigned long) - 1); }
+
+struct Memory
+{
+ Region_list *ram;
+ Region_list *regions;
+ unsigned long find_free_ram(unsigned long size, unsigned long min_addr = 0,
+ unsigned long max_addr = ~0UL);
+ unsigned long find_free_ram_rev(unsigned long size, unsigned long min_addr = 0,
+ unsigned long max_addr = ~0UL);
+};
+
+/**
+ * Interface to boot modules.
+ *
+ * Boot modules can for example be loaded by GRUB, or may be linked
+ * into bootstrap.
+ */
+class Boot_modules
+{
+public:
+
+ /// Main information for each module.
+ struct Module
+ {
+ char const *start;
+ char const *end;
+ char const *cmdline;
+
+ unsigned long size() const { return end -start; }
+ };
+
+ static char const *const Mod_reg;
+
+ virtual ~Boot_modules() = 0;
+ virtual void reserve() = 0;
+ virtual Module module(unsigned index, bool uncompress = true) const = 0;
+ virtual unsigned num_modules() const = 0;
+ virtual l4util_mb_info_t *construct_mbi(unsigned long mod_addr) = 0;
+ virtual void move_module(unsigned index, void *dest,
+ bool overlap_check = true) = 0;
+ void move_modules(unsigned long modaddr);
+ Region mod_region(unsigned index, l4_addr_t start, l4_addr_t size,
+ Region::Type type = Region::Boot);
+ void merge_mod_regions();
+
+protected:
+ void _move_module(unsigned index, void *dest, void const *src,
+ unsigned long size, bool overlap_check);
+};
+
+inline Boot_modules::~Boot_modules() {}
+
+class Platform_base
+{
+public:
+ virtual ~Platform_base() = 0;
+ virtual void init() = 0;
+ virtual void setup_memory_map() = 0;
+ virtual Boot_modules *modules() = 0;
+ virtual bool probe() = 0;
+
+ virtual l4_uint64_t to_phys(l4_addr_t bootstrap_addr)
+ { return bootstrap_addr; }
+
+ virtual l4_addr_t to_virt(l4_uint64_t phys_addr)
+ { return phys_addr; }
+
+ virtual void reboot()
+ {
+ while (1)
+ ;
+ }
+
+ virtual void arm_switch_to_hyp() {}
+
+ virtual void boot_kernel(unsigned long entry)
+ {
+ typedef void (*func)(void);
+ ((func)entry)();
+ exit(-100);
+ }
+
+ // remember the chosen platform
+ static Platform_base *platform;
+
+ // find a platform
+ static void iterate_platforms()
+ {
+ extern Platform_base *__PLATFORMS_BEGIN[];
+ extern Platform_base *__PLATFORMS_END[];
+ for (Platform_base **p = __PLATFORMS_BEGIN; p < __PLATFORMS_END; ++p)
+ if (*p && (*p)->probe())
+ {
+ platform = *p;
+ platform->init();
+ break;
+ }
+ }
+};
+
+inline Platform_base::~Platform_base() {}
+
+#define REGISTER_PLATFORM(type) \
+ static type type##_inst; \
+ static type * const __attribute__((section(".platformdata"),used)) type##_inst_p = &type##_inst
+
+
+#ifdef IMAGE_MODE
+
+/**
+ * For image mode we have this utility that implements
+ * handling of linked in modules.
+ */
+class Boot_modules_image_mode : public Boot_modules
+{
+public:
+ void reserve();
+ Module module(unsigned index, bool uncompress) const;
+ unsigned num_modules() const;
+ void move_module(unsigned index, void *dest,
+ bool overlap_check = true);
+ l4util_mb_info_t *construct_mbi(unsigned long mod_addr);
+
+private:
+ void decompress_mods(unsigned mod_count, unsigned skip,
+ l4_addr_t total_size, l4_addr_t mod_addr);
+};
+
+
+class Platform_single_region_ram : public Platform_base,
+ public Boot_modules_image_mode
+{
+public:
+ Boot_modules *modules() { return this; }
+ void setup_memory_map();
+};
+
+#endif
+
+extern Memory *mem_manager;
+
+#endif /* __BOOTSTRAP__SUPPORT_H__ */
--- /dev/null
+/*
+ * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ * Frank Mehnert <fm3@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#ifndef __TYPES_H__
+#define __TYPES_H__
+
+#include <l4/sys/consts.h>
+
+#define MODS_MAX 128
+#define CMDLINE_MAX 1024
+#define MOD_NAME_MAX 1024
+
+typedef char __mb_mod_name_str[MOD_NAME_MAX];
+
+// info where the page table is, for 64bit mode only
+struct ptab64_mem_info_t
+{
+ l4_uint32_t addr;
+ l4_uint32_t size;
+};
+
+#endif /* ! __TYPES_H__ */
--- /dev/null
+/**
+ * \file bootstrap/server/src/uncompress.c
+ * \brief Support for on-the-fly uncompressing of boot modules
+ *
+ * \date 2004
+ * \author Adam Lackorzynski <adam@os.inf.tu-dresden.de> */
+
+/*
+ * (c) 2005-2009 Author(s)
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <l4/sys/l4int.h>
+#include <l4/sys/consts.h>
+
+#include "startup.h"
+#include "gunzip.h"
+#include "uncompress.h"
+
+static void *filestart;
+
+enum { lin_alloc_buffer_size = 12 << 10 };
+unsigned long lin_alloc_buffer[(lin_alloc_buffer_size + sizeof(unsigned long) - 1)/ sizeof(unsigned long)];
+
+/*
+ * Upper address for the allocator for gunzip
+ */
+l4_addr_t
+gunzip_upper_mem_linalloc(void)
+{
+ return (l4_addr_t)lin_alloc_buffer + sizeof(lin_alloc_buffer);
+}
+
+/*
+ * Returns true if file is compressed, false if not
+ */
+static void
+file_open(void *start, int size)
+{
+ filepos = 0;
+ filestart = start;
+ filemax = size;
+ fsmax = 0xffffffff; /* just big */
+ compressed_file = 0;
+
+ gunzip_test_header();
+}
+
+static int
+module_read(void *buf, int size)
+{
+ memcpy(buf, (const void *)((l4_addr_t)filestart + filepos), size);
+ filepos += size;
+ return size;
+}
+
+int
+grub_read(unsigned char *buf, int len)
+{
+ /* Make sure "filepos" is a sane value */
+ if (/*(filepos < 0) || */(filepos > filemax))
+ filepos = filemax;
+
+ /* Make sure "len" is a sane value */
+ if ((len < 0) || (len > (signed)(filemax - filepos)))
+ len = filemax - filepos;
+
+ /* if target file position is past the end of
+ the supported/configured filesize, then
+ there is an error */
+ if (filepos + len > fsmax)
+ {
+ printf("Filesize error %d + %d > %d\n", filepos, len, fsmax);
+ return 0;
+ }
+
+ if (compressed_file)
+ return gunzip_read (buf, len);
+
+ return module_read(buf, len);
+}
+
+void*
+decompress(const char *name, void *start, void *destbuf,
+ int size, int size_uncompressed)
+{
+ int read_size;
+
+ if (!size_uncompressed)
+ return NULL;
+
+ file_open(start, size);
+
+ // don't move data around if the data isn't compressed
+ if (!compressed_file)
+ return start;
+
+ printf(" Uncompressing %s from %p to %p (%d to %d bytes, %+lld%%).\n",
+ name, start, destbuf, size, size_uncompressed,
+ 100*(unsigned long long)size_uncompressed/size - 100);
+
+ // Add 10 to detect too short given size
+ if ((read_size = grub_read(destbuf, size_uncompressed + 10))
+ != size_uncompressed)
+ {
+ printf("Uncorrect decompression: should be %d bytes but got %d bytes. Errnum = %d\n",
+ size_uncompressed, read_size, errnum);
+ return NULL;
+ }
+
+ return destbuf;
+}
--- /dev/null
+/*
+ * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ * economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#ifndef __BOOTSTRAP__UNCOMPRESS_H__
+#define __BOOTSTRAP__UNCOMPRESS_H__
+
+#include <l4/sys/compiler.h>
+
+EXTERN_C_BEGIN
+
+void *decompress(const char *name, void *start, void *destbuf,
+ int size, int size_uncompressed);
+
+EXTERN_C_END
+
+#endif /* ! __BOOTSTRAP__UNCOMPRESS_H__ */
--- /dev/null
+#! /usr/bin/perl -W
+#
+# by Adam Lackorzynski
+#
+# Simple attack at unpacking a bootstrap-image again. A smarter way would
+# probably be if we'd add some clear marks in the image when generating
+# it...
+#
+# Todo: prettification
+
+use strict;
+
+my @phdrs;
+my $filename = shift;
+die "Need to give filename!" unless defined $filename;
+
+system("arm-linux-objcopy -j .data -O binary $filename unpack.data");
+die "objcopy failed" if $?;
+
+# make it easy, just hold the file parts in memory
+my $unpackdata;
+my $allfile;
+open(A, "unpack.data") || die "Cannot open: $!";
+{
+ local undef $/;
+ $unpackdata = <A>;
+}
+close A;
+
+open(A, $filename) || die "Cannot open: $!";
+{
+ local undef $/;
+ $allfile = <A>;
+}
+close A;
+
+sub find_offset($)
+{
+ my $vaddr = shift;
+ die "find_offset: EINVAL" unless defined $vaddr;
+
+ foreach my $p (@phdrs) {
+ if ($vaddr > @$p{vaddr} && @$p{vaddr} + @$p{memsize} >= $vaddr) {
+ return $vaddr - @$p{vaddr} + @$p{fileoff};
+ }
+ }
+ die "find_phdr unsuccessful";
+}
+
+sub get_string($)
+{
+ unpack("Z*", substr($allfile, find_offset(shift)));
+}
+
+sub get_blob($$)
+{
+ my $vaddr = shift;
+ my $len = shift;
+ substr($allfile, find_offset($vaddr), $len);
+}
+
+# parse $filename PHDRs
+{
+ my $o = `objdump -p $filename`;
+
+ foreach (split / LOAD /, $o) {
+ if (/off\s+0x([a-fA-F0-9]+)\s+vaddr\s+0x([a-fA-F0-9]+)\s+paddr\s+0x[a-fA-F0-9]+\s+align\s+\d\*\*\d+\s*.\s+filesz\s+0x([a-fA-F0-9]+)\s+memsz\s+0x([a-fA-F0-9]+)/m) {
+ print "PHDR: off=$1 vaddr=$2 fsz=$3 msz=$4\n";
+ push @phdrs, { fileoff => hex($1), vaddr => hex($2), filesize => hex($3), memsize => hex($4) };
+ }
+ }
+}
+
+my $filesize = -s "$filename";
+
+my $offset = 0;
+my %entries;
+my $previous;
+my $delta = 4;
+my $modinfo_size = 24;
+while ($offset < length($unpackdata) - 12 * 4) {
+ my ($start0, $size0, $sizeun0, $name0, $md5comp0, $md5uncomp0,
+ $start1, $size1, $sizeun1, $name1, $md5comp1, $md5uncomp1,
+ $start2, $size2, $sizeun2, $name2, $md5comp2, $md5uncomp2)
+ = unpack("LLLLLLLLLLLLLLLLLL", substr($unpackdata, $offset));
+
+ if ((!defined $previous || $previous + $modinfo_size == $offset)
+ && ($start0 > 0x5000)
+ && ($start1 > 0x5000)
+ && ($start2 > 0x5000)
+ && (($start0 & 0xfff) == 0)
+ && (($start1 & 0xfff) == 0)
+ && (($start2 & 0xfff) == 0)
+ && ($size0 < $filesize)
+ && ($size1 < $filesize)
+ && ($size2 < $filesize)
+ && ($sizeun0 < (80 << 20))
+ && ($sizeun1 < (80 << 20))
+ && ($sizeun2 < (80 << 20))) {
+
+ #printf "%x %x %x\n", $start0, $start1, $start2;
+ printf "Found module info at offset %d/0x%x\n", $offset, $offset;
+
+ $entries{$offset}{addr} = $start0;
+ $entries{$offset}{size} = $size0;
+ $entries{$offset}{usize} = $sizeun0;
+ $entries{$offset}{name} = $name0;
+ $entries{$offset}{md5comp} = $md5comp0;
+ $entries{$offset}{md5uncomp} = $md5uncomp0;
+ $entries{$offset + 1 * $modinfo_size}{addr} = $start1;
+ $entries{$offset + 1 * $modinfo_size}{size} = $size1;
+ $entries{$offset + 1 * $modinfo_size}{usize} = $sizeun1;
+ $entries{$offset + 1 * $modinfo_size}{name} = $name1;
+ $entries{$offset + 1 * $modinfo_size}{md5comp} = $md5comp1;
+ $entries{$offset + 1 * $modinfo_size}{md5uncomp} = $md5uncomp1;
+ $entries{$offset + 2 * $modinfo_size}{addr} = $start2;
+ $entries{$offset + 2 * $modinfo_size}{size} = $size2;
+ $entries{$offset + 2 * $modinfo_size}{usize} = $sizeun2;
+ $entries{$offset + 2 * $modinfo_size}{name} = $name2;
+ $entries{$offset + 2 * $modinfo_size}{md5comp} = $md5comp2;
+ $entries{$offset + 2 * $modinfo_size}{md5uncomp} = $md5uncomp2;
+
+ $previous = $offset;
+ $delta = $modinfo_size;
+ } else {
+ $delta = 4;
+ }
+ $offset += $delta;
+
+ print "Scanning at offset $offset\n" if $offset % 1000 == 0;
+}
+
+my $dir = "unpack.dir";
+mkdir $dir;
+
+open(MODLIST, ">$dir/modules.list")
+ || die "Cannot open $dir/unpack.modules.list: $!";
+print MODLIST "entry unpacked\n";
+print MODLIST "modaddr 0x01200000\n";
+
+my $nr = 1;
+open(M, ">md5sums") || die "Cannot create checksum file: $!";
+foreach my $e (sort { $a <=> $b } keys %entries)
+{
+ my $name = get_string($entries{$e}{name});
+ my $fname = "$dir/$name";
+ open(A, ">$fname") || die "Cannot create file $fname: $!";
+ print A get_blob($entries{$e}{addr}, $entries{$e}{size});
+ close A;
+
+ print M get_string($entries{$e}{md5uncomp})." $fname\n";
+
+
+ system("file $fname");
+
+ # missing: cmdlines
+ if ($nr == 1) {
+ print MODLIST "kernel $name\n";
+ } elsif ($nr == 2) {
+ print MODLIST "sigma0 $name\n";
+ } elsif ($nr == 3) {
+ print MODLIST "roottask $name\n";
+ } else {
+ print MODLIST "module $name\n";
+ }
+
+
+ $nr++;
+}
+close M;
+close MODLIST;
+
+unlink "unpack.data";
+
+system("md5sum -c md5sums");