xref: /kvmtool/powerpc/kvm.c (revision f17e5a37d51f6ec6d08373b4cfef9d09f01e76ba) !
163e158a0SMatt Evans /*
263e158a0SMatt Evans  * PPC64 (SPAPR) platform support
363e158a0SMatt Evans  *
463e158a0SMatt Evans  * Copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation.
563e158a0SMatt Evans  *
6d391177aSMatt Evans  * Portions of FDT setup borrowed from QEMU, copyright 2010 David Gibson, IBM
7d391177aSMatt Evans  * Corporation.
8d391177aSMatt Evans  *
963e158a0SMatt Evans  * This program is free software; you can redistribute it and/or modify it
1063e158a0SMatt Evans  * under the terms of the GNU General Public License version 2 as published
1163e158a0SMatt Evans  * by the Free Software Foundation.
1263e158a0SMatt Evans  */
1363e158a0SMatt Evans 
1463e158a0SMatt Evans #include "kvm/kvm.h"
1563e158a0SMatt Evans #include "kvm/util.h"
16d391177aSMatt Evans #include "libfdt.h"
17d391177aSMatt Evans #include "cpu_info.h"
1863e158a0SMatt Evans 
19be76823fSMatt Evans #include "spapr.h"
207295767dSMatt Evans #include "spapr_hvcons.h"
21be76823fSMatt Evans 
2263e158a0SMatt Evans #include <linux/kvm.h>
2363e158a0SMatt Evans 
2463e158a0SMatt Evans #include <sys/types.h>
2563e158a0SMatt Evans #include <sys/ioctl.h>
2663e158a0SMatt Evans #include <sys/mman.h>
2763e158a0SMatt Evans #include <stdbool.h>
2863e158a0SMatt Evans #include <stdlib.h>
2963e158a0SMatt Evans #include <string.h>
3063e158a0SMatt Evans #include <unistd.h>
3163e158a0SMatt Evans #include <stdio.h>
3263e158a0SMatt Evans #include <fcntl.h>
3363e158a0SMatt Evans #include <asm/unistd.h>
3463e158a0SMatt Evans #include <errno.h>
3563e158a0SMatt Evans 
3663e158a0SMatt Evans #include <linux/byteorder.h>
37d391177aSMatt Evans 
38d391177aSMatt Evans #define HPT_ORDER 24
3963e158a0SMatt Evans 
4063e158a0SMatt Evans #define HUGETLBFS_PATH "/var/lib/hugetlbfs/global/pagesize-16MB/"
4163e158a0SMatt Evans 
42*f17e5a37SMatt Evans #define PHANDLE_XICP		0x00001111
43*f17e5a37SMatt Evans 
4463e158a0SMatt Evans static char kern_cmdline[2048];
4563e158a0SMatt Evans 
4663e158a0SMatt Evans struct kvm_ext kvm_req_ext[] = {
47*f17e5a37SMatt Evans 	{ DEFINE_KVM_EXT(KVM_CAP_PPC_UNSET_IRQ) },
48*f17e5a37SMatt Evans 	{ DEFINE_KVM_EXT(KVM_CAP_PPC_IRQ_LEVEL) },
4963e158a0SMatt Evans 	{ 0, 0 }
5063e158a0SMatt Evans };
5163e158a0SMatt Evans 
52d391177aSMatt Evans static uint32_t mfpvr(void)
53d391177aSMatt Evans {
54d391177aSMatt Evans 	uint32_t r;
55d391177aSMatt Evans 	asm volatile ("mfpvr %0" : "=r"(r));
56d391177aSMatt Evans 	return r;
57d391177aSMatt Evans }
58d391177aSMatt Evans 
5963e158a0SMatt Evans bool kvm__arch_cpu_supports_vm(void)
6063e158a0SMatt Evans {
6163e158a0SMatt Evans 	return true;
6263e158a0SMatt Evans }
6363e158a0SMatt Evans 
6463e158a0SMatt Evans void kvm__init_ram(struct kvm *kvm)
6563e158a0SMatt Evans {
6663e158a0SMatt Evans 	u64	phys_start, phys_size;
6763e158a0SMatt Evans 	void	*host_mem;
6863e158a0SMatt Evans 
6963e158a0SMatt Evans 	phys_start = 0;
7063e158a0SMatt Evans 	phys_size  = kvm->ram_size;
7163e158a0SMatt Evans 	host_mem   = kvm->ram_start;
7263e158a0SMatt Evans 
7363e158a0SMatt Evans 	/*
7463e158a0SMatt Evans 	 * We put MMIO at PPC_MMIO_START, high up.  Make sure that this doesn't
7563e158a0SMatt Evans 	 * crash into the end of RAM -- on PPC64 at least, this is so high
7663e158a0SMatt Evans 	 * (63TB!) that this is unlikely.
7763e158a0SMatt Evans 	 */
7863e158a0SMatt Evans 	if (phys_size >= PPC_MMIO_START)
7963e158a0SMatt Evans 		die("Too much memory (%lld, what a nice problem): "
8063e158a0SMatt Evans 		    "overlaps MMIO!\n",
8163e158a0SMatt Evans 		    phys_size);
8263e158a0SMatt Evans 
8363e158a0SMatt Evans 	kvm__register_mem(kvm, phys_start, phys_size, host_mem);
8463e158a0SMatt Evans }
8563e158a0SMatt Evans 
8663e158a0SMatt Evans void kvm__arch_set_cmdline(char *cmdline, bool video)
8763e158a0SMatt Evans {
8863e158a0SMatt Evans 	/* We don't need anything unusual in here. */
8963e158a0SMatt Evans }
9063e158a0SMatt Evans 
9163e158a0SMatt Evans /* Architecture-specific KVM init */
927eff9f49SWanlong Gao void kvm__arch_init(struct kvm *kvm, const char *hugetlbfs_path, u64 ram_size)
9363e158a0SMatt Evans {
9463e158a0SMatt Evans 	int cap_ppc_rma;
95df129a0aSMatt Evans 	unsigned long hpt;
9663e158a0SMatt Evans 
9763e158a0SMatt Evans 	kvm->ram_size		= ram_size;
9863e158a0SMatt Evans 
9963e158a0SMatt Evans 	/*
100df129a0aSMatt Evans 	 * Currently, HV-mode PPC64 SPAPR requires that we map from hugetlfs.
101df129a0aSMatt Evans 	 * Allow a 'default' option to assist.
102df129a0aSMatt Evans 	 * PR-mode does not require this.
10363e158a0SMatt Evans 	 */
104df129a0aSMatt Evans 	if (hugetlbfs_path) {
105df129a0aSMatt Evans 		if (!strcmp(hugetlbfs_path, "default"))
10663e158a0SMatt Evans 			hugetlbfs_path = HUGETLBFS_PATH;
10763e158a0SMatt Evans 		kvm->ram_start = mmap_hugetlbfs(hugetlbfs_path, kvm->ram_size);
108df129a0aSMatt Evans 	} else {
109df129a0aSMatt Evans 		kvm->ram_start = mmap(0, kvm->ram_size, PROT_READ | PROT_WRITE,
110df129a0aSMatt Evans 				      MAP_ANON | MAP_PRIVATE,
111df129a0aSMatt Evans 				      -1, 0);
112df129a0aSMatt Evans 	}
11363e158a0SMatt Evans 	if (kvm->ram_start == MAP_FAILED)
11463e158a0SMatt Evans 		die("Couldn't map %lld bytes for RAM (%d)\n",
11563e158a0SMatt Evans 		    kvm->ram_size, errno);
11663e158a0SMatt Evans 
11763e158a0SMatt Evans 	/* FDT goes at top of memory, RTAS just below */
11863e158a0SMatt Evans 	kvm->fdt_gra = kvm->ram_size - FDT_MAX_SIZE;
11963e158a0SMatt Evans 	/* FIXME: Not all PPC systems have RTAS */
12063e158a0SMatt Evans 	kvm->rtas_gra = kvm->fdt_gra - RTAS_MAX_SIZE;
12163e158a0SMatt Evans 	madvise(kvm->ram_start, kvm->ram_size, MADV_MERGEABLE);
12263e158a0SMatt Evans 
123df129a0aSMatt Evans 	/* FIXME:  SPAPR-PR specific; allocate a guest HPT. */
124df129a0aSMatt Evans 	if (posix_memalign((void **)&hpt, (1<<HPT_ORDER), (1<<HPT_ORDER)))
125df129a0aSMatt Evans 		die("Can't allocate %d bytes for HPT\n", (1<<HPT_ORDER));
126df129a0aSMatt Evans 
127df129a0aSMatt Evans 	kvm->sdr1 = ((hpt + 0x3ffffULL) & ~0x3ffffULL) | (HPT_ORDER-18);
128df129a0aSMatt Evans 
129d391177aSMatt Evans 	kvm->pvr = mfpvr();
130d391177aSMatt Evans 
13163e158a0SMatt Evans 	/* FIXME: This is book3s-specific */
13263e158a0SMatt Evans 	cap_ppc_rma = ioctl(kvm->sys_fd, KVM_CHECK_EXTENSION, KVM_CAP_PPC_RMA);
13363e158a0SMatt Evans 	if (cap_ppc_rma == 2)
13463e158a0SMatt Evans 		die("Need contiguous RMA allocation on this hardware, "
13563e158a0SMatt Evans 		    "which is not yet supported.");
136be76823fSMatt Evans 
137be76823fSMatt Evans 	/* Do these before FDT setup, IRQ setup, etc. */
138be76823fSMatt Evans 	/* FIXME: SPAPR-specific */
139be76823fSMatt Evans 	hypercall_init();
140be76823fSMatt Evans 	register_core_rtas();
1417295767dSMatt Evans 	/* Now that hypercalls are initialised, register a couple for the console: */
1427295767dSMatt Evans 	spapr_hvcons_init();
14363e158a0SMatt Evans }
14463e158a0SMatt Evans 
145e56e2de7SLai Jiangshan void kvm__arch_delete_ram(struct kvm *kvm)
146e56e2de7SLai Jiangshan {
147e56e2de7SLai Jiangshan 	munmap(kvm->ram_start, kvm->ram_size);
148e56e2de7SLai Jiangshan }
149e56e2de7SLai Jiangshan 
15063e158a0SMatt Evans void kvm__irq_trigger(struct kvm *kvm, int irq)
15163e158a0SMatt Evans {
15263e158a0SMatt Evans 	kvm__irq_line(kvm, irq, 1);
15363e158a0SMatt Evans 	kvm__irq_line(kvm, irq, 0);
15463e158a0SMatt Evans }
15563e158a0SMatt Evans 
1567295767dSMatt Evans void kvm__arch_periodic_poll(struct kvm *kvm)
1577295767dSMatt Evans {
1587295767dSMatt Evans 	/* FIXME: Should register callbacks to platform-specific polls */
1597295767dSMatt Evans 	spapr_hvcons_poll(kvm);
1607295767dSMatt Evans }
1617295767dSMatt Evans 
16263e158a0SMatt Evans int load_flat_binary(struct kvm *kvm, int fd_kernel, int fd_initrd, const char *kernel_cmdline)
16363e158a0SMatt Evans {
16463e158a0SMatt Evans 	void *p;
16563e158a0SMatt Evans 	void *k_start;
16663e158a0SMatt Evans 	void *i_start;
16763e158a0SMatt Evans 	int nr;
16863e158a0SMatt Evans 
16963e158a0SMatt Evans 	if (lseek(fd_kernel, 0, SEEK_SET) < 0)
17063e158a0SMatt Evans 		die_perror("lseek");
17163e158a0SMatt Evans 
17263e158a0SMatt Evans 	p = k_start = guest_flat_to_host(kvm, KERNEL_LOAD_ADDR);
17363e158a0SMatt Evans 
17463e158a0SMatt Evans 	while ((nr = read(fd_kernel, p, 65536)) > 0)
17563e158a0SMatt Evans 		p += nr;
17663e158a0SMatt Evans 
17763e158a0SMatt Evans 	pr_info("Loaded kernel to 0x%x (%ld bytes)", KERNEL_LOAD_ADDR, p-k_start);
17863e158a0SMatt Evans 
17963e158a0SMatt Evans 	if (fd_initrd != -1) {
18063e158a0SMatt Evans 		if (lseek(fd_initrd, 0, SEEK_SET) < 0)
18163e158a0SMatt Evans 			die_perror("lseek");
18263e158a0SMatt Evans 
18363e158a0SMatt Evans 		if (p-k_start > INITRD_LOAD_ADDR)
18463e158a0SMatt Evans 			die("Kernel overlaps initrd!");
18563e158a0SMatt Evans 
18663e158a0SMatt Evans 		/* Round up kernel size to 8byte alignment, and load initrd right after. */
18763e158a0SMatt Evans 		i_start = p = guest_flat_to_host(kvm, INITRD_LOAD_ADDR);
18863e158a0SMatt Evans 
18963e158a0SMatt Evans 		while (((nr = read(fd_initrd, p, 65536)) > 0) &&
19063e158a0SMatt Evans 		       p < (kvm->ram_start + kvm->ram_size))
19163e158a0SMatt Evans 			p += nr;
19263e158a0SMatt Evans 
19363e158a0SMatt Evans 		if (p >= (kvm->ram_start + kvm->ram_size))
19463e158a0SMatt Evans 			die("initrd too big to contain in guest RAM.\n");
19563e158a0SMatt Evans 
19663e158a0SMatt Evans 		pr_info("Loaded initrd to 0x%x (%ld bytes)",
19763e158a0SMatt Evans 			INITRD_LOAD_ADDR, p-i_start);
19863e158a0SMatt Evans 		kvm->initrd_gra = INITRD_LOAD_ADDR;
19963e158a0SMatt Evans 		kvm->initrd_size = p-i_start;
20063e158a0SMatt Evans 	} else {
20163e158a0SMatt Evans 		kvm->initrd_size = 0;
20263e158a0SMatt Evans 	}
20363e158a0SMatt Evans 	strncpy(kern_cmdline, kernel_cmdline, 2048);
20463e158a0SMatt Evans 	kern_cmdline[2047] = '\0';
20563e158a0SMatt Evans 
20663e158a0SMatt Evans 	return true;
20763e158a0SMatt Evans }
20863e158a0SMatt Evans 
20963e158a0SMatt Evans bool load_bzimage(struct kvm *kvm, int fd_kernel,
21063e158a0SMatt Evans 		  int fd_initrd, const char *kernel_cmdline, u16 vidmode)
21163e158a0SMatt Evans {
21263e158a0SMatt Evans 	/* We don't support bzImages. */
21363e158a0SMatt Evans 	return false;
21463e158a0SMatt Evans }
21563e158a0SMatt Evans 
216d391177aSMatt Evans #define SMT_THREADS 4
217d391177aSMatt Evans 
218d391177aSMatt Evans /*
219d391177aSMatt Evans  * Set up the FDT for the kernel: This function is currently fairly SPAPR-heavy,
220d391177aSMatt Evans  * and whilst most PPC targets will require CPU/memory nodes, others like RTAS
221d391177aSMatt Evans  * should eventually be added separately.
222d391177aSMatt Evans  */
22363e158a0SMatt Evans static void setup_fdt(struct kvm *kvm)
22463e158a0SMatt Evans {
225d391177aSMatt Evans 	uint64_t 	mem_reg_property[] = { 0, cpu_to_be64(kvm->ram_size) };
226d391177aSMatt Evans 	int 		smp_cpus = kvm->nrcpus;
227*f17e5a37SMatt Evans 	uint32_t	int_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
228d391177aSMatt Evans 	char 		hypertas_prop_kvm[] = "hcall-pft\0hcall-term\0"
229d391177aSMatt Evans 		"hcall-dabr\0hcall-interrupt\0hcall-tce\0hcall-vio\0"
230d391177aSMatt Evans 		"hcall-splpar\0hcall-bulk";
231d391177aSMatt Evans 	int 		i, j;
232d391177aSMatt Evans 	char 		cpu_name[30];
233d391177aSMatt Evans 	u8		staging_fdt[FDT_MAX_SIZE];
234d391177aSMatt Evans 	struct cpu_info *cpu_info = find_cpu_info(kvm->pvr);
23563e158a0SMatt Evans 
236d391177aSMatt Evans 	/* Generate an appropriate DT at kvm->fdt_gra */
237d391177aSMatt Evans 	void *fdt_dest = guest_flat_to_host(kvm, kvm->fdt_gra);
238d391177aSMatt Evans 	void *fdt = staging_fdt;
239d391177aSMatt Evans 
240d391177aSMatt Evans 	_FDT(fdt_create(fdt, FDT_MAX_SIZE));
241d391177aSMatt Evans 	_FDT(fdt_finish_reservemap(fdt));
242d391177aSMatt Evans 
243d391177aSMatt Evans 	_FDT(fdt_begin_node(fdt, ""));
244d391177aSMatt Evans 
245d391177aSMatt Evans 	_FDT(fdt_property_string(fdt, "device_type", "chrp"));
246d391177aSMatt Evans 	_FDT(fdt_property_string(fdt, "model", "IBM pSeries (kvmtool)"));
247d391177aSMatt Evans 	_FDT(fdt_property_cell(fdt, "#address-cells", 0x2));
248d391177aSMatt Evans 	_FDT(fdt_property_cell(fdt, "#size-cells", 0x2));
249d391177aSMatt Evans 
250be76823fSMatt Evans 	/* RTAS */
251be76823fSMatt Evans 	_FDT(fdt_begin_node(fdt, "rtas"));
252be76823fSMatt Evans 	/* This is what the kernel uses to switch 'We're an LPAR'! */
253be76823fSMatt Evans         _FDT(fdt_property(fdt, "ibm,hypertas-functions", hypertas_prop_kvm,
254be76823fSMatt Evans                            sizeof(hypertas_prop_kvm)));
255be76823fSMatt Evans 	_FDT(fdt_property_cell(fdt, "linux,rtas-base", kvm->rtas_gra));
256be76823fSMatt Evans 	_FDT(fdt_property_cell(fdt, "linux,rtas-entry", kvm->rtas_gra));
257be76823fSMatt Evans 	_FDT(fdt_property_cell(fdt, "rtas-size", kvm->rtas_size));
258be76823fSMatt Evans 	/* Now add properties for all RTAS tokens: */
259be76823fSMatt Evans 	if (spapr_rtas_fdt_setup(kvm, fdt))
260be76823fSMatt Evans 		die("Couldn't create RTAS FDT properties\n");
261be76823fSMatt Evans 
262be76823fSMatt Evans 	_FDT(fdt_end_node(fdt));
263be76823fSMatt Evans 
264d391177aSMatt Evans 	/* /chosen */
265d391177aSMatt Evans 	_FDT(fdt_begin_node(fdt, "chosen"));
266d391177aSMatt Evans 	/* cmdline */
267d391177aSMatt Evans 	_FDT(fdt_property_string(fdt, "bootargs", kern_cmdline));
268d391177aSMatt Evans 	/* Initrd */
269d391177aSMatt Evans 	if (kvm->initrd_size != 0) {
270d391177aSMatt Evans 		uint32_t ird_st_prop = cpu_to_be32(kvm->initrd_gra);
271d391177aSMatt Evans 		uint32_t ird_end_prop = cpu_to_be32(kvm->initrd_gra +
272d391177aSMatt Evans 						    kvm->initrd_size);
273d391177aSMatt Evans 		_FDT(fdt_property(fdt, "linux,initrd-start",
274d391177aSMatt Evans 				   &ird_st_prop, sizeof(ird_st_prop)));
275d391177aSMatt Evans 		_FDT(fdt_property(fdt, "linux,initrd-end",
276d391177aSMatt Evans 				   &ird_end_prop, sizeof(ird_end_prop)));
277d391177aSMatt Evans 	}
2787295767dSMatt Evans 
2797295767dSMatt Evans 	/*
2807295767dSMatt Evans 	 * stdout-path: This is assuming we're using the HV console.  Also, the
2817295767dSMatt Evans 	 * address is hardwired until we do a VIO bus.
2827295767dSMatt Evans 	 */
2837295767dSMatt Evans 	_FDT(fdt_property_string(fdt, "linux,stdout-path",
2847295767dSMatt Evans 				 "/vdevice/vty@30000000"));
285d391177aSMatt Evans 	_FDT(fdt_end_node(fdt));
286d391177aSMatt Evans 
287d391177aSMatt Evans 	/*
288d391177aSMatt Evans 	 * Memory: We don't alloc. a separate RMA yet.  If we ever need to
289d391177aSMatt Evans 	 * (CAP_PPC_RMA == 2) then have one memory node for 0->RMAsize, and
290d391177aSMatt Evans 	 * another RMAsize->endOfMem.
291d391177aSMatt Evans 	 */
292d391177aSMatt Evans 	_FDT(fdt_begin_node(fdt, "memory@0"));
293d391177aSMatt Evans 	_FDT(fdt_property_string(fdt, "device_type", "memory"));
294d391177aSMatt Evans 	_FDT(fdt_property(fdt, "reg", mem_reg_property,
295d391177aSMatt Evans 			  sizeof(mem_reg_property)));
296d391177aSMatt Evans 	_FDT(fdt_end_node(fdt));
297d391177aSMatt Evans 
298d391177aSMatt Evans 	/* CPUs */
299d391177aSMatt Evans 	_FDT(fdt_begin_node(fdt, "cpus"));
300d391177aSMatt Evans 	_FDT(fdt_property_cell(fdt, "#address-cells", 0x1));
301d391177aSMatt Evans 	_FDT(fdt_property_cell(fdt, "#size-cells", 0x0));
302d391177aSMatt Evans 
303d391177aSMatt Evans 	for (i = 0; i < smp_cpus; i += SMT_THREADS) {
304d391177aSMatt Evans 		int32_t pft_size_prop[] = { 0, HPT_ORDER };
305d391177aSMatt Evans 		uint32_t servers_prop[SMT_THREADS];
306d391177aSMatt Evans 		uint32_t gservers_prop[SMT_THREADS * 2];
307d391177aSMatt Evans 		int threads = (smp_cpus - i) >= SMT_THREADS ? SMT_THREADS :
308d391177aSMatt Evans 			smp_cpus - i;
309d391177aSMatt Evans 
310d391177aSMatt Evans 		sprintf(cpu_name, "PowerPC,%s@%d", cpu_info->name, i);
311d391177aSMatt Evans 		_FDT(fdt_begin_node(fdt, cpu_name));
312d391177aSMatt Evans 		sprintf(cpu_name, "PowerPC,%s", cpu_info->name);
313d391177aSMatt Evans 		_FDT(fdt_property_string(fdt, "name", cpu_name));
314d391177aSMatt Evans 		_FDT(fdt_property_string(fdt, "device_type", "cpu"));
315d391177aSMatt Evans 
316d391177aSMatt Evans 		_FDT(fdt_property_cell(fdt, "reg", i));
317d391177aSMatt Evans 		_FDT(fdt_property_cell(fdt, "cpu-version", kvm->pvr));
318d391177aSMatt Evans 
319d391177aSMatt Evans 		_FDT(fdt_property_cell(fdt, "dcache-block-size", cpu_info->d_bsize));
320d391177aSMatt Evans 		_FDT(fdt_property_cell(fdt, "icache-block-size", cpu_info->i_bsize));
321d391177aSMatt Evans 
322d391177aSMatt Evans 		_FDT(fdt_property_cell(fdt, "timebase-frequency", cpu_info->tb_freq));
323d391177aSMatt Evans 		/* Lies, but safeish lies! */
324d391177aSMatt Evans 		_FDT(fdt_property_cell(fdt, "clock-frequency", 0xddbab200));
325d391177aSMatt Evans 
326d391177aSMatt Evans 		if (cpu_info->slb_size)
327d391177aSMatt Evans 			_FDT(fdt_property_cell(fdt, "ibm,slb-size", cpu_info->slb_size));
328d391177aSMatt Evans 		/*
329d391177aSMatt Evans 		 * HPT size is hardwired; KVM currently fixes it at 16MB but the
330d391177aSMatt Evans 		 * moment that changes we'll need to read it out of the kernel.
331d391177aSMatt Evans 		 */
332d391177aSMatt Evans 		_FDT(fdt_property(fdt, "ibm,pft-size", pft_size_prop,
333d391177aSMatt Evans 				  sizeof(pft_size_prop)));
334d391177aSMatt Evans 
335d391177aSMatt Evans 		_FDT(fdt_property_string(fdt, "status", "okay"));
336d391177aSMatt Evans 		_FDT(fdt_property(fdt, "64-bit", NULL, 0));
337d391177aSMatt Evans 		/* A server for each thread in this core */
338d391177aSMatt Evans 		for (j = 0; j < SMT_THREADS; j++) {
339d391177aSMatt Evans 			servers_prop[j] = cpu_to_be32(i+j);
340d391177aSMatt Evans 			/*
341d391177aSMatt Evans 			 * Hack borrowed from QEMU, direct the group queues back
342d391177aSMatt Evans 			 * to cpu 0:
343d391177aSMatt Evans 			 */
344d391177aSMatt Evans 			gservers_prop[j*2] = cpu_to_be32(i+j);
345d391177aSMatt Evans 			gservers_prop[j*2 + 1] = 0;
346d391177aSMatt Evans 		}
347d391177aSMatt Evans 		_FDT(fdt_property(fdt, "ibm,ppc-interrupt-server#s",
348d391177aSMatt Evans 				   servers_prop, threads * sizeof(uint32_t)));
349d391177aSMatt Evans 		_FDT(fdt_property(fdt, "ibm,ppc-interrupt-gserver#s",
350d391177aSMatt Evans 				  gservers_prop,
351d391177aSMatt Evans 				  threads * 2 * sizeof(uint32_t)));
352d391177aSMatt Evans 		if (cpu_info->page_sizes_prop)
353d391177aSMatt Evans 			_FDT(fdt_property(fdt, "ibm,segment-page-sizes",
354d391177aSMatt Evans 					  cpu_info->page_sizes_prop,
355d391177aSMatt Evans 					  cpu_info->page_sizes_prop_len));
356d391177aSMatt Evans 		if (cpu_info->segment_sizes_prop)
357d391177aSMatt Evans 			_FDT(fdt_property(fdt, "ibm,processor-segment-sizes",
358d391177aSMatt Evans 					  cpu_info->segment_sizes_prop,
359d391177aSMatt Evans 					  cpu_info->segment_sizes_prop_len));
360d391177aSMatt Evans 		/* VSX / DFP options: */
361d391177aSMatt Evans 		if (cpu_info->flags & CPUINFO_FLAG_VMX)
362d391177aSMatt Evans 			_FDT(fdt_property_cell(fdt, "ibm,vmx",
363d391177aSMatt Evans 					       (cpu_info->flags &
364d391177aSMatt Evans 						CPUINFO_FLAG_VSX) ? 2 : 1));
365d391177aSMatt Evans 		if (cpu_info->flags & CPUINFO_FLAG_DFP)
366d391177aSMatt Evans 			_FDT(fdt_property_cell(fdt, "ibm,dfp", 0x1));
367d391177aSMatt Evans 		_FDT(fdt_end_node(fdt));
368d391177aSMatt Evans 	}
369d391177aSMatt Evans 	_FDT(fdt_end_node(fdt));
370d391177aSMatt Evans 
371*f17e5a37SMatt Evans 	/* IRQ controller */
372*f17e5a37SMatt Evans 	_FDT(fdt_begin_node(fdt, "interrupt-controller@0"));
373*f17e5a37SMatt Evans 
374*f17e5a37SMatt Evans 	_FDT(fdt_property_string(fdt, "device_type",
375*f17e5a37SMatt Evans 				 "PowerPC-External-Interrupt-Presentation"));
376*f17e5a37SMatt Evans 	_FDT(fdt_property_string(fdt, "compatible", "IBM,ppc-xicp"));
377*f17e5a37SMatt Evans 	_FDT(fdt_property_cell(fdt, "reg", 0));
378*f17e5a37SMatt Evans 	_FDT(fdt_property(fdt, "interrupt-controller", NULL, 0));
379*f17e5a37SMatt Evans 	_FDT(fdt_property(fdt, "ibm,interrupt-server-ranges",
380*f17e5a37SMatt Evans 			   int_server_ranges_prop,
381*f17e5a37SMatt Evans 			   sizeof(int_server_ranges_prop)));
382*f17e5a37SMatt Evans 	_FDT(fdt_property_cell(fdt, "#interrupt-cells", 2));
383*f17e5a37SMatt Evans 	_FDT(fdt_property_cell(fdt, "linux,phandle", PHANDLE_XICP));
384*f17e5a37SMatt Evans 	_FDT(fdt_property_cell(fdt, "phandle", PHANDLE_XICP));
385*f17e5a37SMatt Evans 	_FDT(fdt_end_node(fdt));
386*f17e5a37SMatt Evans 
3877295767dSMatt Evans 	/*
3887295767dSMatt Evans 	 * VIO: See comment in linux,stdout-path; we don't yet represent a VIO
3897295767dSMatt Evans 	 * bus/address allocation so addresses are hardwired here.
3907295767dSMatt Evans 	 */
3917295767dSMatt Evans 	_FDT(fdt_begin_node(fdt, "vdevice"));
3927295767dSMatt Evans 	_FDT(fdt_property_cell(fdt, "#address-cells", 0x1));
3937295767dSMatt Evans 	_FDT(fdt_property_cell(fdt, "#size-cells", 0x0));
3947295767dSMatt Evans 	_FDT(fdt_property_string(fdt, "device_type", "vdevice"));
3957295767dSMatt Evans 	_FDT(fdt_property_string(fdt, "compatible", "IBM,vdevice"));
3967295767dSMatt Evans 	_FDT(fdt_begin_node(fdt, "vty@30000000"));
3977295767dSMatt Evans 	_FDT(fdt_property_string(fdt, "name", "vty"));
3987295767dSMatt Evans 	_FDT(fdt_property_string(fdt, "device_type", "serial"));
3997295767dSMatt Evans 	_FDT(fdt_property_string(fdt, "compatible", "hvterm1"));
4007295767dSMatt Evans 	_FDT(fdt_property_cell(fdt, "reg", 0x30000000));
4017295767dSMatt Evans 	_FDT(fdt_end_node(fdt));
4027295767dSMatt Evans 	_FDT(fdt_end_node(fdt));
4037295767dSMatt Evans 
404d391177aSMatt Evans 	/* Finalise: */
405d391177aSMatt Evans 	_FDT(fdt_end_node(fdt)); /* Root node */
406d391177aSMatt Evans 	_FDT(fdt_finish(fdt));
407d391177aSMatt Evans 
408d391177aSMatt Evans 	_FDT(fdt_open_into(fdt, fdt_dest, FDT_MAX_SIZE));
409d391177aSMatt Evans 	_FDT(fdt_add_mem_rsv(fdt_dest, kvm->rtas_gra, kvm->rtas_size));
410d391177aSMatt Evans 	_FDT(fdt_pack(fdt_dest));
41163e158a0SMatt Evans }
41263e158a0SMatt Evans 
41363e158a0SMatt Evans /**
41463e158a0SMatt Evans  * kvm__arch_setup_firmware
41563e158a0SMatt Evans  */
416f7f9d02bSCyrill Gorcunov int kvm__arch_setup_firmware(struct kvm *kvm)
41763e158a0SMatt Evans {
418be76823fSMatt Evans 	/*
419be76823fSMatt Evans 	 * Set up RTAS stub.  All it is is a single hypercall:
420be76823fSMatt Evans 	 *  0:   7c 64 1b 78     mr      r4,r3
421be76823fSMatt Evans 	 *  4:   3c 60 00 00     lis     r3,0
422be76823fSMatt Evans 	 *  8:   60 63 f0 00     ori     r3,r3,61440
423be76823fSMatt Evans 	 *  c:   44 00 00 22     sc      1
424be76823fSMatt Evans 	 * 10:   4e 80 00 20     blr
425be76823fSMatt Evans 	 */
426be76823fSMatt Evans 	uint32_t *rtas = guest_flat_to_host(kvm, kvm->rtas_gra);
427be76823fSMatt Evans 
428be76823fSMatt Evans 	rtas[0] = 0x7c641b78;
429be76823fSMatt Evans 	rtas[1] = 0x3c600000;
430be76823fSMatt Evans 	rtas[2] = 0x6063f000;
431be76823fSMatt Evans 	rtas[3] = 0x44000022;
432be76823fSMatt Evans 	rtas[4] = 0x4e800020;
433be76823fSMatt Evans 	kvm->rtas_size = 20;
434be76823fSMatt Evans 
435be76823fSMatt Evans 	pr_info("Set up %ld bytes of RTAS at 0x%lx\n",
436be76823fSMatt Evans 		kvm->rtas_size, kvm->rtas_gra);
43763e158a0SMatt Evans 
43863e158a0SMatt Evans 	/* Load SLOF */
43963e158a0SMatt Evans 
44063e158a0SMatt Evans 	/* Init FDT */
44163e158a0SMatt Evans 	setup_fdt(kvm);
442f7f9d02bSCyrill Gorcunov 
443f7f9d02bSCyrill Gorcunov 	return 0;
44463e158a0SMatt Evans }
4451add9f73SSasha Levin 
4461add9f73SSasha Levin int kvm__arch_free_firmware(struct kvm *kvm)
4471add9f73SSasha Levin {
4481add9f73SSasha Levin 	return 0;
4491add9f73SSasha Levin }
450