aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/ia64/xensetup.c
blob: e669ae51e71ef5a0cbc446a5c502a7b42ed25fe1 (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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
/******************************************************************************
 * xensetup.c
 * Copyright (c) 2004-2005  Hewlett-Packard Co
 *         Dan Magenheimer <dan.magenheimer@hp.com>
 */

#include <xen/config.h>
#include <xen/lib.h>
#include <xen/errno.h>
//#include <xen/spinlock.h>
#include <xen/multiboot.h>
#include <xen/sched.h>
#include <xen/mm.h>
//#include <xen/delay.h>
#include <xen/compile.h>
//#include <xen/console.h>
//#include <xen/serial.h>
#include <xen/trace.h>
#include <asm/meminit.h>
#include <asm/page.h>
#include <asm/setup.h>
#include <xen/string.h>

unsigned long xenheap_phys_end;

char saved_command_line[COMMAND_LINE_SIZE];

struct vcpu *idle_task[NR_CPUS] = { &idle0_vcpu };

#ifdef CLONE_DOMAIN0
struct domain *clones[CLONE_DOMAIN0];
#endif
extern struct domain *dom0;
extern unsigned long domain0_ready;

int find_max_pfn (unsigned long, unsigned long, void *);
void start_of_day(void);

/* opt_nosmp: If true, secondary processors are ignored. */
static int opt_nosmp = 0;
boolean_param("nosmp", opt_nosmp);

/* maxcpus: maximum number of CPUs to activate. */
static unsigned int max_cpus = NR_CPUS;
integer_param("maxcpus", max_cpus); 

/*
 * opt_xenheap_megabytes: Size of Xen heap in megabytes, including:
 *	xen image
 *	bootmap bits
 *	xen heap
 * Note: To allow xenheap size configurable, the prerequisite is
 * to configure elilo allowing relocation defaultly. Then since
 * elilo chooses 256M as alignment when relocating, alignment issue
 * on IPF can be addressed.
 */
unsigned int opt_xenheap_megabytes = XENHEAP_DEFAULT_MB;
unsigned long xenheap_size = XENHEAP_DEFAULT_SIZE;
extern long running_on_sim;
unsigned long xen_pstart;

static int
xen_count_pages(u64 start, u64 end, void *arg)
{
    unsigned long *count = arg;

    /* FIXME: do we need consider difference between DMA-usable memory and
     * normal memory? Seems that HV has no requirement to operate DMA which
     * is owned by Dom0? */
    *count += (end - start) >> PAGE_SHIFT;
    return 0;
}

/* Find first hole after trunk for xen image */
static int
xen_find_first_hole(u64 start, u64 end, void *arg)
{
    unsigned long *first_hole = arg;

    if ((*first_hole) == 0) {
	if ((start <= KERNEL_START) && (KERNEL_START < end))
	    *first_hole = __pa(end);
    }

    return 0;
}

static void __init do_initcalls(void)
{
    initcall_t *call;
    for ( call = &__initcall_start; call < &__initcall_end; call++ )
        (*call)();
}

/*
 * IPF loader only supports one commaind line currently, for
 * both xen and guest kernel. This function provides pre-parse
 * to mixed command line, to split it into two parts.
 *
 * User should split the parameters by "--", with strings after
 * spliter for guest kernel. Missing "--" means whole line belongs
 * to guest. Example:
 *	"com2=57600,8n1 console=com2 -- console=ttyS1 console=tty
 * root=/dev/sda3 ro"
 */
static char null[4] = { 0 };

void early_cmdline_parse(char **cmdline_p)
{
    char *guest_cmd;
    char *split = "--";

    if (*cmdline_p == NULL) {
	*cmdline_p = &null[0];
	saved_command_line[0] = '\0';
	return;
    }

    guest_cmd = strstr(*cmdline_p, split);
    /* If no spliter, whole line is for guest */
    if (guest_cmd == NULL) {
	guest_cmd = *cmdline_p;
	*cmdline_p = &null[0];
    } else {
	*guest_cmd = '\0';	/* Split boot parameters for xen and guest */
	guest_cmd += strlen(split);
	while (*guest_cmd == ' ') guest_cmd++;
    }

    strlcpy(saved_command_line, guest_cmd, COMMAND_LINE_SIZE);
    return;
}

void start_kernel(void)
{
    unsigned char *cmdline;
    void *heap_start;
    int i;
    unsigned long max_mem, nr_pages, firsthole_start;
    unsigned long dom0_memory_start, dom0_memory_end;
    unsigned long initial_images_start, initial_images_end;

    running_on_sim = is_platform_hp_ski();
    /* Kernel may be relocated by EFI loader */
    xen_pstart = ia64_tpa(KERNEL_START);

    /* Must do this early -- e.g., spinlocks rely on get_current(). */
    //set_current(&idle0_vcpu);
    ia64_r13 = (void *)&idle0_vcpu;
    idle0_vcpu.domain = &idle0_domain;

    early_setup_arch(&cmdline);

    /* We initialise the serial devices very early so we can get debugging. */
    if (running_on_sim) hpsim_serial_init();
    else ns16550_init();
    serial_init_preirq();

    init_console();
    set_printk_prefix("(XEN) ");

    /* xenheap should be in same TR-covered range with xen image */
    xenheap_phys_end = xen_pstart + xenheap_size;
    printk("xen image pstart: 0x%lx, xenheap pend: 0x%lx\n",
	    xen_pstart, xenheap_phys_end);

#ifdef CONFIG_VTI
    /* If we want to enable vhpt for all regions, related initialization
     * for HV TLB must be done earlier before first TLB miss
     */
#endif // CONFIG_VTI
    /* Find next hole */
    firsthole_start = 0;
    efi_memmap_walk(xen_find_first_hole, &firsthole_start);

    initial_images_start = xenheap_phys_end;
    initial_images_end = initial_images_start + ia64_boot_param->initrd_size;

    /* Later may find another memory trunk, even away from xen image... */
    if (initial_images_end > firsthole_start) {
	printk("Not enough memory to stash the DOM0 kernel image.\n");
	printk("First hole:0x%lx, relocation end: 0x%lx\n",
		firsthole_start, initial_images_end);
	for ( ; ; );
    }

    /* This copy is time consuming, but elilo may load Dom0 image
     * within xenheap range */
    printk("ready to move Dom0 to 0x%lx...", initial_images_start);
    memmove(__va(initial_images_start),
	   __va(ia64_boot_param->initrd_start),
	   ia64_boot_param->initrd_size);
    ia64_boot_param->initrd_start = initial_images_start;
    printk("Done\n");

    /* first find highest page frame number */
    max_page = 0;
    efi_memmap_walk(find_max_pfn, &max_page);
    printf("find_memory: efi_memmap_walk returns max_page=%lx\n",max_page);

    heap_start = memguard_init(ia64_imva(&_end));
    printf("Before heap_start: 0x%lx\n", heap_start);
    heap_start = __va(init_boot_allocator(__pa(heap_start)));
    printf("After heap_start: 0x%lx\n", heap_start);

    reserve_memory();

    efi_memmap_walk(filter_rsvd_memory, init_boot_pages);
    efi_memmap_walk(xen_count_pages, &nr_pages);

    printk("System RAM: %luMB (%lukB)\n",
	nr_pages >> (20 - PAGE_SHIFT),
	nr_pages << (PAGE_SHIFT - 10));

    init_frametable();

    alloc_dom0();
#ifdef DOMU_BUILD_STAGING
    alloc_domU_staging();
#endif

    end_boot_allocator();

    init_xenheap_pages(__pa(heap_start), xenheap_phys_end);
    printk("Xen heap: %luMB (%lukB)\n",
	(xenheap_phys_end-__pa(heap_start)) >> 20,
	(xenheap_phys_end-__pa(heap_start)) >> 10);

    late_setup_arch(&cmdline);
    setup_per_cpu_areas();
    mem_init();

printk("About to call scheduler_init()\n");
    scheduler_init();
    local_irq_disable();
printk("About to call xen_time_init()\n");
    xen_time_init();
#ifdef CONFIG_VTI
    init_xen_time(); /* initialise the time */
#endif // CONFIG_VTI 
printk("About to call ac_timer_init()\n");
    ac_timer_init();
// init_xen_time(); ???
    schedulers_start();
    do_initcalls();
printk("About to call sort_main_extable()\n");
    sort_main_extable();

    /* Create initial domain 0. */
printk("About to call do_createdomain()\n");
    dom0 = do_createdomain(0, 0);
    init_task.domain = &idle0_domain;
    init_task.processor = 0;
//    init_task.mm = &init_mm;
    init_task.domain->arch.mm = &init_mm;
//    init_task.thread = INIT_THREAD;
    //arch_do_createdomain(current);
#ifdef CLONE_DOMAIN0
    {
    int i;
    for (i = 0; i < CLONE_DOMAIN0; i++) {
	clones[i] = do_createdomain(i+1, 0);
        if ( clones[i] == NULL )
            panic("Error creating domain0 clone %d\n",i);
    }
    }
#endif
    if ( dom0 == NULL )
        panic("Error creating domain 0\n");

    set_bit(_DOMF_privileged, &dom0->domain_flags);

    /*
     * We're going to setup domain0 using the module(s) that we stashed safely
     * above our heap. The second module, if present, is an initrd ramdisk.
     */
printk("About to call construct_dom0()\n");
    dom0_memory_start = __va(ia64_boot_param->initrd_start);
    dom0_memory_end = ia64_boot_param->initrd_size;
    if ( construct_dom0(dom0, dom0_memory_start, dom0_memory_end,
			0,
                        0,
			0) != 0)
        panic("Could not set up DOM0 guest OS\n");
#ifdef CLONE_DOMAIN0
    {
    int i;
    dom0_memory_start = __va(ia64_boot_param->initrd_start);
    dom0_memory_end = ia64_boot_param->initrd_size;
    for (i = 0; i < CLONE_DOMAIN0; i++) {
printk("CONSTRUCTING DOMAIN0 CLONE #%d\n",i+1);
        if ( construct_domU(clones[i], dom0_memory_start, dom0_memory_end,
                        0, 
                        0,
			0) != 0)
            panic("Could not set up DOM0 clone %d\n",i);
    }
    }
#endif

    /* The stash space for the initial kernel image can now be freed up. */
    init_domheap_pages(ia64_boot_param->initrd_start,
		       ia64_boot_param->initrd_start + ia64_boot_param->initrd_size);
    if (!running_on_sim)  // slow on ski and pages are pre-initialized to zero
	scrub_heap_pages();

printk("About to call init_trace_bufs()\n");
    init_trace_bufs();

    /* Give up the VGA console if DOM0 is configured to grab it. */
#ifndef IA64
    console_endboot(cmdline && strstr(cmdline, "tty0"));
#endif

#ifdef CLONE_DOMAIN0
    {
    int i;
    for (i = 0; i < CLONE_DOMAIN0; i++)
	domain_unpause_by_systemcontroller(clones[i]);
    }
#endif
    domain_unpause_by_systemcontroller(dom0);
    domain0_ready = 1;
    local_irq_enable();
printk("About to call startup_cpu_idle_loop()\n");
    startup_cpu_idle_loop();
}