aboutsummaryrefslogtreecommitdiffstats
path: root/src/flags.ads
blob: 096d889c04638c524a8b2bbedfcd9e7f99466e34 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
--  Global flags.
--  Copyright (C) 2002, 2003, 2004, 2005, 2008 Tristan Gingold
--
--  GHDL 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, or (at your option) any later
--  version.
--
--  GHDL 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 GHDL; see the file COPYING.  If not, write to the Free
--  Software Foundation, 59 Temple Place - Suite 330, Boston, MA
--  02111-1307, USA.

--  All the variables declared in this package are set by Parse_Option function
--  and can by read as soon as the command line is parsed.
--
--  Since the names are not prefixed, this package is expected to be with'ed
--  but not to be use'd.

package Flags is
   --  List of vhdl standards.
   --  VHDL_93c is vhdl_93 with backward compatibility with 87 (file).
   type Vhdl_Std_Type is
     (Vhdl_87, Vhdl_93c, Vhdl_93, Vhdl_00, Vhdl_02, Vhdl_08);

   --  Standard accepted.
   Vhdl_Std: Vhdl_Std_Type := Vhdl_93c;

   --  Enable AMS-VHDL extensions.
   AMS_Vhdl : Boolean := False;

   --  Some flags (such as vhdl version) must be the same for every design
   --  units of a hierarchy.
   --  The Flag_String is a signature of all these flags.
   --  Note: Flag_String (5) (time resolution) is directly overwritten in
   --   ghdlrun.
   Flag_String : String (1 .. 5);
   procedure Create_Flag_String;

   -- If set, a multi-bytes sequence can appear in a comment, ie, all
   -- characters except VT, CR, LF and FF are allowed in a comment.
   -- Set by -C and --mb-comments
   Mb_Comment: Boolean := False;

   -- If set, relax rules about std library: working library can be std.
   Bootstrap : Boolean := False;

   --  Options -dX
   --  -dp: disp tree after parsing
   Dump_Parse: Boolean := False;

   --  -ds: disp tree after semantic
   Dump_Sem: Boolean := False;

   --  -dc: disp tree after canon
   Dump_Canon : Boolean := False;

   --  -da: disp tree after annotation
   Dump_Annotate: Boolean := False;

   --  -do: don't dump origin expression but evaluated expressions.
   Dump_Origin_Flag : Boolean := True;

   --  --dall: makes -dX options to apply to all files.
   Dump_All: Boolean := False;

   --  -dstats: disp statistics.
   Dump_Stats : Boolean := False;

   --  If not 0, do internal consistency and leaks check on the AST after
   --  analysis.
   Check_Ast_Level : Natural := 0;

   -- -lX options: list tree as a vhdl file.

   -- --lall option: makes -lX options to apply to all files
   List_All: Boolean := False;

   -- -lv: list verbose
   List_Verbose: Boolean := False;

   -- -ls: list tree after semantic.
   List_Sem: Boolean := False;

   -- -lc: list tree after canon.
   List_Canon: Boolean := False;

   -- -la: list tree after back-end annotation.
   List_Annotate: Boolean := False;

   -- -v: disp phase of compilation.
   Verbose : Boolean := False;

   --  If set to true, the parser builds extended locations (defined in
   --  package elocations).  This saves possibly many locations per node, so
   --  it uses more memory.  Useful when a tool (like a style checker) wants
   --  to know the precise layout.  Not used to report errors.
   Flag_Elocations : Boolean := False;

   --  If set to true, it means that analyze is done for elaboration.
   --  The purpose is to avoid spurious warning "will be checked
   --  at elaboration"
   Flag_Elaborate : Boolean := False;

   --  If set, a default aspect entity aspect might be an outdated unit.
   --  Used by ghdldrv.
   Flag_Elaborate_With_Outdated : Boolean := False;

   --  Do not display parse and sem warnings.  Used during elaboration.
   Flag_Only_Elab_Warnings : Boolean := False;

   --  If set, explicit subprogram declarations take precedence over
   --  implicit declarations, even through use clauses.
   Flag_Explicit : Boolean := False;

   --  If set, use 'L.C' rule from VHDL02 to do default component binding.
   Flag_Syn_Binding : Boolean := False;

   --  If set, performs VITAL checks.
   Flag_Vital_Checks : Boolean := True;

   --  Set if analysis is done even after parsing errors.  The analysis code
   --  that handles and tolerates incorrect parse tree should check that this
   --  flag is set.
   Flag_Force_Analysis : Boolean := False;

   --  Integer and time types can be either 32 bits or 64 bits values.
   --  The default is 32 bits for Integer and 64 bits for Time.
   --  Be very careful: if you don't use the default sizes, you may have to
   --  change other parts of your systems (such as GRT).
   Flag_Integer_64 : Boolean := False;
   Flag_Time_64 : Boolean := True;

   --  If set, generate cross-references during sem.
   Flag_Xref : Boolean := False;

   --  If set, all the design units are analyzed in whole to do the simulation.
   Flag_Whole_Analyze : Boolean := False;

   --  If true, relax some rules:
   --  * the scope of an object declaration names start after the declaration,
   --    so that it is possible to use the old name in the default expression:
   --    constant x : xtype := x;
   Flag_Relaxed_Rules : Boolean := False;

   -- --warn-undriven
   --Warn_Undriven : Boolean := False;

   --  --warn-error
   --  Turns warnings into errors.
   Warn_Error : Boolean := False;

   --  If True, disp original source line and a caret indicating the column.
   Flag_Caret_Diagnostics : Boolean := False;

   type On_Off_Auto_Type is (On, Off, Auto);

   --  -fcolor-diagnostics
   --  -fno-color-diagnostics
   --  Enable colors in diagnostic messages.  The default is auto, which turns
   --  on when a terminal is detected on the standard error.
   Flag_Color_Diagnostics : On_Off_Auto_Type := Auto;

   --  -fdiagnostics-show-option
   Flag_Diagnostics_Show_Option : Boolean := True;
end Flags;
neric.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
/*
 *  Copyright (C) 1995  Linus Torvalds
 *
 *  Pentium III FXSR, SSE support
 *	Gareth Hughes <gareth@valinux.com>, May 2000
 */

#include <xen/config.h>
#include <xen/lib.h>
#include <xen/errno.h>
#include <xen/sched.h>
#include <xen/smp.h>
#include <xen/delay.h>
#include <xen/softirq.h>
#include <xen/mm.h>
#include <asm/ptrace.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/processor.h>
#include <asm/desc.h>
//#include <asm/mpspec.h>
#include <xen/irq.h>
#include <xen/event.h>
//#include <xen/shadow.h>
#include <xen/console.h>

#include <xen/elf.h>
//#include <asm/page.h>
#include <asm/pgalloc.h>
#include <asm/dma.h>	/* for MAX_DMA_ADDRESS */

#include <asm/asm-offsets.h>  /* for IA64_THREAD_INFO_SIZE */

#include <asm/vcpu.h>   /* for function declarations */

#define CONFIG_DOMAIN0_CONTIGUOUS
unsigned long dom0_start = -1L;
unsigned long dom0_size = 512*1024*1024; //FIXME: Should be configurable
//FIXME: alignment should be 256MB, lest Linux use a 256MB page size
unsigned long dom0_align = 64*1024*1024;

extern kmem_cache_t *domain_struct_cachep;

// initialized by arch/ia64/setup.c:find_initrd()
unsigned long initrd_start = 0, initrd_end = 0;

extern int loadelfimage(char *);
extern int readelfimage_base_and_size(char *, unsigned long,
                  unsigned long *, unsigned long *, unsigned long *);

unsigned long map_domain_page0(struct domain *);
extern unsigned long dom_fw_setup(struct domain *, char *, int);

/* this belongs in include/asm, but there doesn't seem to be a suitable place */
void free_perdomain_pt(struct domain *d)
{
    dummy();
    //free_page((unsigned long)d->mm.perdomain_pt);
}

int hlt_counter;

void disable_hlt(void)
{
    hlt_counter++;
}

void enable_hlt(void)
{
    hlt_counter--;
}

static void default_idle(void)
{
    if ( hlt_counter == 0 )
    {
	local_irq_disable();
        if ( !softirq_pending(smp_processor_id()) )
            safe_halt();
        //else
		local_irq_enable();
    }
}

void continue_cpu_idle_loop(void)
{
    int cpu = smp_processor_id();
    for ( ; ; )
    {
#ifdef IA64
//        __IRQ_STAT(cpu, idle_timestamp) = jiffies
#else
        irq_stat[cpu].idle_timestamp = jiffies;
#endif
        while ( !softirq_pending(cpu) )
            default_idle();
        do_softirq();
    }
}

void startup_cpu_idle_loop(void)
{
    /* Just some sanity to ensure that the scheduler is set up okay. */
    ASSERT(current->domain == IDLE_DOMAIN_ID);
    domain_unpause_by_systemcontroller(current->domain);
    __enter_scheduler();

    /*
     * Declares CPU setup done to the boot processor.
     * Therefore memory barrier to ensure state is visible.
     */
    smp_mb();
    init_idle();
#if 0
//do we have to ensure the idle task has a shared page so that, for example,
//region registers can be loaded from it.  Apparently not...
	idle0_task.shared_info = (void *)alloc_xenheap_page();
	memset(idle0_task.shared_info, 0, PAGE_SIZE);
	/* pin mapping */
	// FIXME: Does this belong here?  Or do only at domain switch time?
	{
		/* WARNING: following must be inlined to avoid nested fault */
		unsigned long psr = ia64_clear_ic();
		ia64_itr(0x2, IA64_TR_SHARED_INFO, SHAREDINFO_ADDR,
		 pte_val(pfn_pte(ia64_tpa(idle0_task.shared_info) >> PAGE_SHIFT, PAGE_KERNEL)),
		 PAGE_SHIFT);
		ia64_set_psr(psr);
		ia64_srlz_i();
	}
#endif

    continue_cpu_idle_loop();
}

struct domain *arch_alloc_domain_struct(void)
{
	return xmem_cache_alloc(domain_struct_cachep);
}

void arch_free_domain_struct(struct domain *d)
{
	xmem_cache_free(domain_struct_cachep,d);
}

struct exec_domain *arch_alloc_exec_domain_struct(void)
{
	return alloc_task_struct();
}

void arch_free_exec_domain_struct(struct exec_domain *ed)
{
	free_task_struct(ed);
}

void arch_do_createdomain(struct exec_domain *ed)
{
	struct domain *d = ed->domain;

	d->shared_info = (void *)alloc_xenheap_page();
	ed->vcpu_info = (void *)alloc_xenheap_page();
	if (!ed->vcpu_info) {
   		printk("ERROR/HALTING: CAN'T ALLOC PAGE\n");
   		while (1);
	}
	memset(ed->vcpu_info, 0, PAGE_SIZE);
	/* pin mapping */
	// FIXME: Does this belong here?  Or do only at domain switch time?
#if 0
	// this is now done in ia64_new_rr7
	{
		/* WARNING: following must be inlined to avoid nested fault */
		unsigned long psr = ia64_clear_ic();
		ia64_itr(0x2, IA64_TR_SHARED_INFO, SHAREDINFO_ADDR,
		 pte_val(pfn_pte(ia64_tpa(d->shared_info) >> PAGE_SHIFT, PAGE_KERNEL)),
		 PAGE_SHIFT);
		ia64_set_psr(psr);
		ia64_srlz_i();
	}
#endif
	d->max_pages = (128*1024*1024)/PAGE_SIZE; // 128MB default // FIXME
	if ((d->metaphysical_rid = allocate_metaphysical_rid()) == -1UL)
		BUG();
	ed->vcpu_info->arch.metaphysical_mode = 1;
#define DOMAIN_RID_BITS_DEFAULT 18
	if (!allocate_rid_range(d,DOMAIN_RID_BITS_DEFAULT)) // FIXME
		BUG();
	// the following will eventually need to be negotiated dynamically
	d->xen_vastart = 0xfffc000000000000;
	d->xen_vaend = 0xfffe000000000000;
	d->shared_info_va = 0xfffd000000000000;
	d->breakimm = 0x1000;
	// stay on kernel stack because may get interrupts!
	// ia64_ret_from_clone (which b0 gets in new_thread) switches
	// to user stack
	ed->thread.on_ustack = 0;
}

void arch_do_boot_vcpu(struct exec_domain *p)
{
	return;
}

int arch_final_setup_guest(struct exec_domain *p, full_execution_context_t *c)
{
	dummy();
	return 1;
}

void domain_relinquish_memory(struct domain *d)
{
	dummy();
}

// heavily leveraged from linux/arch/ia64/kernel/process.c:copy_thread()
// and linux/arch/ia64/kernel/process.c:kernel_thread()
void new_thread(struct exec_domain *ed,
                unsigned long start_pc,
                unsigned long start_stack,
                unsigned long start_info)
{
	struct domain *d = ed->domain;
	struct switch_stack *sw;
	struct pt_regs *regs;
	unsigned long new_rbs;
	struct ia64_boot_param *bp;
	extern char ia64_ret_from_clone;
	extern char saved_command_line[];

#ifdef CONFIG_DOMAIN0_CONTIGUOUS
	if (d == dom0) start_pc += dom0_start;
#endif
	regs = (struct pt_regs *) ((unsigned long) ed + IA64_STK_OFFSET) - 1;
	sw = (struct switch_stack *) regs - 1;
	new_rbs = (unsigned long) ed + IA64_RBS_OFFSET;
	regs->cr_ipsr = ia64_getreg(_IA64_REG_PSR)
		| IA64_PSR_BITS_TO_SET | IA64_PSR_BN
		& ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_RI | IA64_PSR_IS);
	regs->cr_ipsr |= 2UL << IA64_PSR_CPL0_BIT; // domain runs at PL2
	regs->cr_iip = start_pc;
	regs->ar_rsc = 0xf;		/* eager mode, privilege level 1 */
	regs->ar_rnat = 0;
	regs->ar_fpsr = sw->ar_fpsr = FPSR_DEFAULT;
	regs->loadrs = 0;
	//regs->r8 = current->mm->dumpable; /* set "don't zap registers" flag */
	//regs->r8 = 0x01234567890abcdef; // FIXME: temp marker
	//regs->r12 = ((unsigned long) regs - 16);	/* 16 byte scratch */
	regs->cr_ifs = 1UL << 63;
	regs->pr = 0;
	sw->pr = 0;
	regs->ar_pfs = 0;
	sw->caller_unat = 0;
	sw->ar_pfs = 0;
	sw->ar_bspstore = new_rbs;
	//regs->r13 = (unsigned long) ed;
printf("new_thread: ed=%p, regs=%p, sw=%p, new_rbs=%p, IA64_STK_OFFSET=%p, &r8=%p\n",
ed,regs,sw,new_rbs,IA64_STK_OFFSET,&regs->r8);
	sw->b0 = (unsigned long) &ia64_ret_from_clone;
	ed->thread.ksp = (unsigned long) sw - 16;
	//ed->thread_info->flags = 0;
printk("new_thread, about to call init_all_rr\n");
	init_all_rr(ed);
	// set up boot parameters (and fake firmware)
printk("new_thread, about to call dom_fw_setup\n");
	regs->r28 = dom_fw_setup(d,saved_command_line,256L);  //FIXME
printk("new_thread, done with dom_fw_setup\n");
	// don't forget to set this!
	ed->vcpu_info->arch.banknum = 1;
}

static struct page * map_new_domain0_page(unsigned long mpaddr)
{
	if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) {
		printk("map_new_domain0_page: bad domain0 mpaddr %p!\n",mpaddr);
printk("map_new_domain0_page: start=%p,end=%p!\n",dom0_start,dom0_start+dom0_size);
		while(1);
	}
	return pfn_to_page((mpaddr >> PAGE_SHIFT));
}

/* allocate new page for domain and map it to the specified metaphysical addr */
struct page * map_new_domain_page(struct domain *d, unsigned long mpaddr)
{
	struct mm_struct *mm = d->arch.mm;
	struct page *p = (struct page *)0;
	pgd_t *pgd;
	pmd_t *pmd;
	pte_t *pte;
extern unsigned long vhpt_paddr, vhpt_pend;

	if (!mm->pgd) {
		printk("map_new_domain_page: domain pgd must exist!\n");
		return(p);
	}
	pgd = pgd_offset(mm,mpaddr);
	if (pgd_none(*pgd))
		pgd_populate(mm, pgd, pmd_alloc_one(mm,mpaddr));

	pmd = pmd_offset(pgd, mpaddr);
	if (pmd_none(*pmd))
		pmd_populate(mm, pmd, pte_alloc_one(mm,mpaddr));

	pte = pte_offset_map(pmd, mpaddr);
	if (pte_none(*pte)) {
#ifdef CONFIG_DOMAIN0_CONTIGUOUS
		if (d == dom0) p = map_new_domain0_page(mpaddr);
		else
#endif
			p = alloc_page(GFP_KERNEL);
		if (unlikely(!p)) {
printf("map_new_domain_page: Can't alloc!!!! Aaaargh!\n");
			return(p);
		}
if (unlikely(page_to_phys(p) > vhpt_paddr && page_to_phys(p) < vhpt_pend)) {
  printf("map_new_domain_page: reassigned vhpt page %p!!\n",page_to_phys(p));
}
		set_pte(pte, pfn_pte(page_to_phys(p) >> PAGE_SHIFT,
			__pgprot(__DIRTY_BITS | _PAGE_PL_2 | _PAGE_AR_RWX)));
	}
	else printk("map_new_domain_page: page %p already mapped!\n",p);
	return p;
}

void mpafoo(unsigned long mpaddr)
{
	extern unsigned long privop_trace;
	if (mpaddr == 0x3800)
		privop_trace = 1;
}

unsigned long lookup_domain_mpa(struct domain *d, unsigned long mpaddr)
{
	struct mm_struct *mm = d->arch.mm;
	pgd_t *pgd = pgd_offset(mm, mpaddr);
	pmd_t *pmd;
	pte_t *pte;

#ifdef CONFIG_DOMAIN0_CONTIGUOUS
	if (d == dom0) {
		if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) {
			//printk("lookup_domain_mpa: bad dom0 mpaddr %p!\n",mpaddr);
//printk("lookup_domain_mpa: start=%p,end=%p!\n",dom0_start,dom0_start+dom0_size);
			mpafoo(mpaddr);
		}
		pte_t pteval = pfn_pte(mpaddr >> PAGE_SHIFT,
			__pgprot(__DIRTY_BITS | _PAGE_PL_2 | _PAGE_AR_RWX));
		pte = &pteval;
		return *(unsigned long *)pte;
	}
#endif
tryagain:
	if (pgd_present(*pgd)) {
		pmd = pmd_offset(pgd,mpaddr);
		if (pmd_present(*pmd)) {
			pte = pte_offset_map(pmd,mpaddr);
			if (pte_present(*pte)) {
//printk("lookup_domain_page: found mapping for %lx, pte=%lx\n",mpaddr,pte_val(*pte));
				return *(unsigned long *)pte;
			}
		}	
	}
	/* if lookup fails and mpaddr is "legal", "create" the page */
	if ((mpaddr >> PAGE_SHIFT) < d->max_pages) {
		// FIXME: should zero out pages for security reasons
		if (map_new_domain_page(d,mpaddr)) goto tryagain;
	}
	printk("lookup_domain_mpa: bad mpa %p (> %p\n",
		mpaddr,d->max_pages<<PAGE_SHIFT);
	mpafoo(mpaddr);
	return 0;
}

// FIXME: ONLY USE FOR DOMAIN PAGE_SIZE == PAGE_SIZE
unsigned long domain_mpa_to_imva(struct domain *d, unsigned long mpaddr)
{
	unsigned long pte = lookup_domain_mpa(d,mpaddr);
	unsigned long imva;

	pte &= _PAGE_PPN_MASK;
	imva = __va(pte);
	imva |= mpaddr & ~PAGE_MASK;
	return(imva);
}

// remove following line if not privifying in memory
//#define HAVE_PRIVIFY_MEMORY
#ifndef HAVE_PRIVIFY_MEMORY
#define	privify_memory(x,y) do {} while(0)
#endif

// see arch/x86/xxx/domain_build.c
int elf_sanity_check(Elf_Ehdr *ehdr)
{
	return (IS_ELF(*ehdr));
}

void loaddomainelfimage(struct domain *d, unsigned long image_start)
{
    char *elfbase = image_start;
    Elf_Ehdr *ehdr = (Elf_Ehdr *)image_start;
    Elf_Phdr *phdr;
    int h, filesz, memsz, paddr;
    unsigned long elfaddr, dom_mpaddr, dom_imva;
    struct page *p;
  
    for ( h = 0; h < ehdr->e_phnum; h++ ) {
        phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize));
        //if ( !is_loadable_phdr(phdr) )
        if ((phdr->p_type != PT_LOAD)) {
            continue;
	}
	filesz = phdr->p_filesz; memsz = phdr->p_memsz;
	elfaddr = elfbase + phdr->p_offset;
	dom_mpaddr = phdr->p_paddr;
//printf("p_offset: %x, size=%x\n",elfaddr,filesz);
#ifdef CONFIG_DOMAIN0_CONTIGUOUS
	if (d == dom0) {
		if (dom_mpaddr+memsz>dom0_size || dom_mpaddr+filesz>dom0_size) {
			printf("Domain0 doesn't fit in allocated space!\n");
			while(1);
		}
		dom_imva = __va(dom_mpaddr + dom0_start);
		memcpy(dom_imva,elfaddr,filesz);
		if (memsz > filesz) memset(dom_imva+filesz,0,memsz-filesz);
//FIXME: This test for code seems to find a lot more than objdump -x does
		if (phdr->p_flags & PF_X) privify_memory(dom_imva,filesz);
	}
	else
#endif
	while (memsz > 0) {
		p = map_new_domain_page(d,dom_mpaddr);
		if (unlikely(!p)) BUG();
		dom_imva = __va(page_to_phys(p));
		if (filesz > 0) {
			if (filesz >= PAGE_SIZE)
				memcpy(dom_imva,elfaddr,PAGE_SIZE);
			else { // copy partial page, zero the rest of page
				memcpy(dom_imva,elfaddr,filesz);
				memset(dom_imva+filesz,0,PAGE_SIZE-filesz);
			}
//FIXME: This test for code seems to find a lot more than objdump -x does
			if (phdr->p_flags & PF_X)
				privify_memory(dom_imva,PAGE_SIZE);
		}
		else if (memsz > 0) // always zero out entire page
			memset(dom_imva,0,PAGE_SIZE);
		memsz -= PAGE_SIZE; filesz -= PAGE_SIZE;
		elfaddr += PAGE_SIZE; dom_mpaddr += PAGE_SIZE;
	}
    }
}


void alloc_dom0(void)
{
#ifdef CONFIG_DOMAIN0_CONTIGUOUS
    if (platform_is_hp_ski()) {
	dom0_size = 128*1024*1024; //FIXME: Should be configurable
    }
    printf("alloc_dom0: starting (initializing %d MB...)\n",dom0_size/(1024*1024));
    dom0_start = __alloc_bootmem(dom0_size,dom0_align,__pa(MAX_DMA_ADDRESS));
    if (!dom0_start) {
	printf("construct_dom0: can't allocate contiguous memory size=%p\n",
		dom0_size);
	while(1);
    }
    printf("alloc_dom0: dom0_start=%p\n",dom0_start);
#else
    dom0_start = 0;
#endif

}

int construct_dom0(struct domain *d, 
                   unsigned long image_start, unsigned long image_len, 
                   unsigned long initrd_start, unsigned long initrd_len,
                   char *cmdline)
{
    char *dst;
    int i, rc;
    unsigned long pfn, mfn;
    unsigned long nr_pt_pages;
    unsigned long count;
    //l2_pgentry_t *l2tab, *l2start;
    //l1_pgentry_t *l1tab = NULL, *l1start = NULL;
    struct pfn_info *page = NULL;
    start_info_t *si;
    struct exec_domain *ed = d->exec_domain[0];

    struct domain_setup_info dsi;
    unsigned long p_start;
    unsigned long pkern_start;
    unsigned long pkern_entry;
    unsigned long pkern_end;

    extern void physdev_init_dom0(struct domain *);

//printf("construct_dom0: starting\n");
    /* Sanity! */
#ifndef CLONE_DOMAIN0
    if ( d != dom0 ) 
        BUG();
    if ( test_bit(DF_CONSTRUCTED, &d->d_flags) ) 
        BUG();
#endif

    memset(&dsi, 0, sizeof(struct domain_setup_info));

    printk("*** LOADING DOMAIN 0 ***\n");

	d->max_pages = dom0_size/PAGE_SIZE;
	image_start = __va(ia64_boot_param->initrd_start);
	image_len = ia64_boot_param->initrd_size;
//printk("image_start=%lx, image_len=%lx\n",image_start,image_len);
//printk("First word of image: %lx\n",*(unsigned long *)image_start);

//printf("construct_dom0: about to call parseelfimage\n");
    rc = parseelfimage(image_start, image_len, &dsi);
    if ( rc != 0 )
        return rc;

    p_start = dsi.v_start;
    pkern_start = dsi.v_kernstart;
    pkern_end = dsi.v_kernend;
    pkern_entry = dsi.v_kernentry;

//printk("p_start=%lx, pkern_start=%lx, pkern_end=%lx, pkern_entry=%lx\n",p_start,pkern_start,pkern_end,pkern_entry);

    if ( (p_start & (PAGE_SIZE-1)) != 0 )
    {
        printk("Initial guest OS must load to a page boundary.\n");
        return -EINVAL;
    }

    printk("METAPHYSICAL MEMORY ARRANGEMENT:\n"
           " Kernel image:  %lx->%lx\n"
           " Entry address: %lx\n"
           " Init. ramdisk:   (NOT IMPLEMENTED YET)\n",
           pkern_start, pkern_end, pkern_entry);

    if ( (pkern_end - pkern_start) > (d->max_pages * PAGE_SIZE) )
    {
        printk("Initial guest OS requires too much space\n"
               "(%luMB is greater than %luMB limit)\n",
               (pkern_end-pkern_start)>>20, (d->max_pages<<PAGE_SHIFT)>>20);
        return -ENOMEM;
    }

    // if high 3 bits of pkern start are non-zero, error

    // if pkern end is after end of metaphysical memory, error
    //  (we should be able to deal with this... later)


    //

#if 0
    strcpy(d->name,"Domain0");
#endif

	// prepare domain0 pagetable (maps METAphysical to physical)
	// following is roughly mm_init() in linux/kernel/fork.c
	d->arch.mm = kmem_cache_alloc(mm_cachep, SLAB_KERNEL);
	if (unlikely(!d->arch.mm)) {
        	printk("Can't allocate mm_struct for domain0\n");
        	return -ENOMEM;
	}
	memset(d->arch.mm, 0, sizeof(*d->arch.mm));
	d->arch.mm->pgd = pgd_alloc(d->arch.mm);
	if (unlikely(!d->arch.mm->pgd)) {
        	printk("Can't allocate pgd for domain0\n");
        	return -ENOMEM;
	}


    /* Mask all upcalls... */
    for ( i = 0; i < MAX_VIRT_CPUS; i++ )
        d->shared_info->vcpu_data[i].evtchn_upcall_mask = 1;

    /* Copy the OS image. */
    //(void)loadelfimage(image_start);
	loaddomainelfimage(d,image_start);

    /* Copy the initial ramdisk. */
    //if ( initrd_len != 0 )
    //    memcpy((void *)vinitrd_start, initrd_start, initrd_len);

#if 0
    /* Set up start info area. */
    //si = (start_info_t *)vstartinfo_start;
    memset(si, 0, PAGE_SIZE);
    si->nr_pages     = d->tot_pages;
    si->shared_info  = virt_to_phys(d->shared_info);
    si->flags        = SIF_PRIVILEGED | SIF_INITDOMAIN;
    //si->pt_base      = vpt_start;
    //si->nr_pt_frames = nr_pt_pages;
    //si->mfn_list     = vphysmap_start;

    if ( initrd_len != 0 )
    {
        //si->mod_start = vinitrd_start;
        si->mod_len   = initrd_len;
        printk("Initrd len 0x%lx, start at 0x%08lx\n",
               si->mod_len, si->mod_start);
    }

    dst = si->cmd_line;
    if ( cmdline != NULL )
    {
        for ( i = 0; i < 255; i++ )
        {
            if ( cmdline[i] == '\0' )
                break;
            *dst++ = cmdline[i];
        }
    }
    *dst = '\0';

    zap_low_mappings(); /* Do the same for the idle page tables. */
#endif
    
    /* Give up the VGA console if DOM0 is configured to grab it. */
#ifdef IA64
	if (cmdline != NULL)
#endif
    console_endboot(strstr(cmdline, "tty0") != NULL);

    /* DOM0 gets access to everything. */
#ifdef CLONE_DOMAIN0
if (d == dom0)
#endif
    physdev_init_dom0(d);

    set_bit(DF_CONSTRUCTED, &d->d_flags);

    new_thread(ed, pkern_entry, 0, 0);
    // FIXME: Hack for keyboard input
#ifdef CLONE_DOMAIN0
if (d == dom0)
#endif
    serial_input_init();
    if (d == dom0) {
    	ed->vcpu_info->arch.delivery_mask[0] = -1L;
    	ed->vcpu_info->arch.delivery_mask[1] = -1L;
    	ed->vcpu_info->arch.delivery_mask[2] = -1L;
    	ed->vcpu_info->arch.delivery_mask[3] = -1L;
    }
    else __set_bit(0x30,ed->vcpu_info->arch.delivery_mask);

    return 0;
}

void machine_restart(char * __unused)
{
	if (platform_is_hp_ski()) dummy();
	printf("machine_restart called: spinning....\n");
	while(1);
}

void machine_halt(void)
{
	if (platform_is_hp_ski()) dummy();
	printf("machine_halt called: spinning....\n");
	while(1);
}

void dummy(void)
{
	if (platform_is_hp_ski()) asm("break 0;;");
	printf("dummy called: spinning....\n");
	while(1);
}


#if 0
void switch_to(struct exec_domain *prev, struct exec_domain *next)
{
 	struct exec_domain *last;

	__switch_to(prev,next,last);
	//set_current(next);
}
#endif

void domain_pend_keyboard_interrupt(int irq)
{
	vcpu_pend_interrupt(dom0->exec_domain[0],irq);
}