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 19*be76823fSMatt Evans #include "spapr.h" 20*be76823fSMatt Evans 2163e158a0SMatt Evans #include <linux/kvm.h> 2263e158a0SMatt Evans 2363e158a0SMatt Evans #include <sys/types.h> 2463e158a0SMatt Evans #include <sys/ioctl.h> 2563e158a0SMatt Evans #include <sys/mman.h> 2663e158a0SMatt Evans #include <stdbool.h> 2763e158a0SMatt Evans #include <stdlib.h> 2863e158a0SMatt Evans #include <string.h> 2963e158a0SMatt Evans #include <unistd.h> 3063e158a0SMatt Evans #include <stdio.h> 3163e158a0SMatt Evans #include <fcntl.h> 3263e158a0SMatt Evans #include <asm/unistd.h> 3363e158a0SMatt Evans #include <errno.h> 3463e158a0SMatt Evans 3563e158a0SMatt Evans #include <linux/byteorder.h> 36d391177aSMatt Evans 37d391177aSMatt Evans #define HPT_ORDER 24 3863e158a0SMatt Evans 3963e158a0SMatt Evans #define HUGETLBFS_PATH "/var/lib/hugetlbfs/global/pagesize-16MB/" 4063e158a0SMatt Evans 4163e158a0SMatt Evans static char kern_cmdline[2048]; 4263e158a0SMatt Evans 4363e158a0SMatt Evans struct kvm_ext kvm_req_ext[] = { 4463e158a0SMatt Evans { 0, 0 } 4563e158a0SMatt Evans }; 4663e158a0SMatt Evans 47d391177aSMatt Evans static uint32_t mfpvr(void) 48d391177aSMatt Evans { 49d391177aSMatt Evans uint32_t r; 50d391177aSMatt Evans asm volatile ("mfpvr %0" : "=r"(r)); 51d391177aSMatt Evans return r; 52d391177aSMatt Evans } 53d391177aSMatt Evans 5463e158a0SMatt Evans bool kvm__arch_cpu_supports_vm(void) 5563e158a0SMatt Evans { 5663e158a0SMatt Evans return true; 5763e158a0SMatt Evans } 5863e158a0SMatt Evans 5963e158a0SMatt Evans void kvm__init_ram(struct kvm *kvm) 6063e158a0SMatt Evans { 6163e158a0SMatt Evans u64 phys_start, phys_size; 6263e158a0SMatt Evans void *host_mem; 6363e158a0SMatt Evans 6463e158a0SMatt Evans phys_start = 0; 6563e158a0SMatt Evans phys_size = kvm->ram_size; 6663e158a0SMatt Evans host_mem = kvm->ram_start; 6763e158a0SMatt Evans 6863e158a0SMatt Evans /* 6963e158a0SMatt Evans * We put MMIO at PPC_MMIO_START, high up. Make sure that this doesn't 7063e158a0SMatt Evans * crash into the end of RAM -- on PPC64 at least, this is so high 7163e158a0SMatt Evans * (63TB!) that this is unlikely. 7263e158a0SMatt Evans */ 7363e158a0SMatt Evans if (phys_size >= PPC_MMIO_START) 7463e158a0SMatt Evans die("Too much memory (%lld, what a nice problem): " 7563e158a0SMatt Evans "overlaps MMIO!\n", 7663e158a0SMatt Evans phys_size); 7763e158a0SMatt Evans 7863e158a0SMatt Evans kvm__register_mem(kvm, phys_start, phys_size, host_mem); 7963e158a0SMatt Evans } 8063e158a0SMatt Evans 8163e158a0SMatt Evans void kvm__arch_set_cmdline(char *cmdline, bool video) 8263e158a0SMatt Evans { 8363e158a0SMatt Evans /* We don't need anything unusual in here. */ 8463e158a0SMatt Evans } 8563e158a0SMatt Evans 8663e158a0SMatt Evans /* Architecture-specific KVM init */ 877eff9f49SWanlong Gao void kvm__arch_init(struct kvm *kvm, const char *hugetlbfs_path, u64 ram_size) 8863e158a0SMatt Evans { 8963e158a0SMatt Evans int cap_ppc_rma; 90df129a0aSMatt Evans unsigned long hpt; 9163e158a0SMatt Evans 9263e158a0SMatt Evans kvm->ram_size = ram_size; 9363e158a0SMatt Evans 9463e158a0SMatt Evans /* 95df129a0aSMatt Evans * Currently, HV-mode PPC64 SPAPR requires that we map from hugetlfs. 96df129a0aSMatt Evans * Allow a 'default' option to assist. 97df129a0aSMatt Evans * PR-mode does not require this. 9863e158a0SMatt Evans */ 99df129a0aSMatt Evans if (hugetlbfs_path) { 100df129a0aSMatt Evans if (!strcmp(hugetlbfs_path, "default")) 10163e158a0SMatt Evans hugetlbfs_path = HUGETLBFS_PATH; 10263e158a0SMatt Evans kvm->ram_start = mmap_hugetlbfs(hugetlbfs_path, kvm->ram_size); 103df129a0aSMatt Evans } else { 104df129a0aSMatt Evans kvm->ram_start = mmap(0, kvm->ram_size, PROT_READ | PROT_WRITE, 105df129a0aSMatt Evans MAP_ANON | MAP_PRIVATE, 106df129a0aSMatt Evans -1, 0); 107df129a0aSMatt Evans } 10863e158a0SMatt Evans if (kvm->ram_start == MAP_FAILED) 10963e158a0SMatt Evans die("Couldn't map %lld bytes for RAM (%d)\n", 11063e158a0SMatt Evans kvm->ram_size, errno); 11163e158a0SMatt Evans 11263e158a0SMatt Evans /* FDT goes at top of memory, RTAS just below */ 11363e158a0SMatt Evans kvm->fdt_gra = kvm->ram_size - FDT_MAX_SIZE; 11463e158a0SMatt Evans /* FIXME: Not all PPC systems have RTAS */ 11563e158a0SMatt Evans kvm->rtas_gra = kvm->fdt_gra - RTAS_MAX_SIZE; 11663e158a0SMatt Evans madvise(kvm->ram_start, kvm->ram_size, MADV_MERGEABLE); 11763e158a0SMatt Evans 118df129a0aSMatt Evans /* FIXME: SPAPR-PR specific; allocate a guest HPT. */ 119df129a0aSMatt Evans if (posix_memalign((void **)&hpt, (1<<HPT_ORDER), (1<<HPT_ORDER))) 120df129a0aSMatt Evans die("Can't allocate %d bytes for HPT\n", (1<<HPT_ORDER)); 121df129a0aSMatt Evans 122df129a0aSMatt Evans kvm->sdr1 = ((hpt + 0x3ffffULL) & ~0x3ffffULL) | (HPT_ORDER-18); 123df129a0aSMatt Evans 124d391177aSMatt Evans kvm->pvr = mfpvr(); 125d391177aSMatt Evans 12663e158a0SMatt Evans /* FIXME: This is book3s-specific */ 12763e158a0SMatt Evans cap_ppc_rma = ioctl(kvm->sys_fd, KVM_CHECK_EXTENSION, KVM_CAP_PPC_RMA); 12863e158a0SMatt Evans if (cap_ppc_rma == 2) 12963e158a0SMatt Evans die("Need contiguous RMA allocation on this hardware, " 13063e158a0SMatt Evans "which is not yet supported."); 131*be76823fSMatt Evans 132*be76823fSMatt Evans /* Do these before FDT setup, IRQ setup, etc. */ 133*be76823fSMatt Evans /* FIXME: SPAPR-specific */ 134*be76823fSMatt Evans hypercall_init(); 135*be76823fSMatt Evans register_core_rtas(); 13663e158a0SMatt Evans } 13763e158a0SMatt Evans 138e56e2de7SLai Jiangshan void kvm__arch_delete_ram(struct kvm *kvm) 139e56e2de7SLai Jiangshan { 140e56e2de7SLai Jiangshan munmap(kvm->ram_start, kvm->ram_size); 141e56e2de7SLai Jiangshan } 142e56e2de7SLai Jiangshan 14363e158a0SMatt Evans void kvm__irq_line(struct kvm *kvm, int irq, int level) 14463e158a0SMatt Evans { 14563e158a0SMatt Evans fprintf(stderr, "irq_line(%d, %d)\n", irq, level); 14663e158a0SMatt Evans } 14763e158a0SMatt Evans 14863e158a0SMatt Evans void kvm__irq_trigger(struct kvm *kvm, int irq) 14963e158a0SMatt Evans { 15063e158a0SMatt Evans kvm__irq_line(kvm, irq, 1); 15163e158a0SMatt Evans kvm__irq_line(kvm, irq, 0); 15263e158a0SMatt Evans } 15363e158a0SMatt Evans 15463e158a0SMatt Evans int load_flat_binary(struct kvm *kvm, int fd_kernel, int fd_initrd, const char *kernel_cmdline) 15563e158a0SMatt Evans { 15663e158a0SMatt Evans void *p; 15763e158a0SMatt Evans void *k_start; 15863e158a0SMatt Evans void *i_start; 15963e158a0SMatt Evans int nr; 16063e158a0SMatt Evans 16163e158a0SMatt Evans if (lseek(fd_kernel, 0, SEEK_SET) < 0) 16263e158a0SMatt Evans die_perror("lseek"); 16363e158a0SMatt Evans 16463e158a0SMatt Evans p = k_start = guest_flat_to_host(kvm, KERNEL_LOAD_ADDR); 16563e158a0SMatt Evans 16663e158a0SMatt Evans while ((nr = read(fd_kernel, p, 65536)) > 0) 16763e158a0SMatt Evans p += nr; 16863e158a0SMatt Evans 16963e158a0SMatt Evans pr_info("Loaded kernel to 0x%x (%ld bytes)", KERNEL_LOAD_ADDR, p-k_start); 17063e158a0SMatt Evans 17163e158a0SMatt Evans if (fd_initrd != -1) { 17263e158a0SMatt Evans if (lseek(fd_initrd, 0, SEEK_SET) < 0) 17363e158a0SMatt Evans die_perror("lseek"); 17463e158a0SMatt Evans 17563e158a0SMatt Evans if (p-k_start > INITRD_LOAD_ADDR) 17663e158a0SMatt Evans die("Kernel overlaps initrd!"); 17763e158a0SMatt Evans 17863e158a0SMatt Evans /* Round up kernel size to 8byte alignment, and load initrd right after. */ 17963e158a0SMatt Evans i_start = p = guest_flat_to_host(kvm, INITRD_LOAD_ADDR); 18063e158a0SMatt Evans 18163e158a0SMatt Evans while (((nr = read(fd_initrd, p, 65536)) > 0) && 18263e158a0SMatt Evans p < (kvm->ram_start + kvm->ram_size)) 18363e158a0SMatt Evans p += nr; 18463e158a0SMatt Evans 18563e158a0SMatt Evans if (p >= (kvm->ram_start + kvm->ram_size)) 18663e158a0SMatt Evans die("initrd too big to contain in guest RAM.\n"); 18763e158a0SMatt Evans 18863e158a0SMatt Evans pr_info("Loaded initrd to 0x%x (%ld bytes)", 18963e158a0SMatt Evans INITRD_LOAD_ADDR, p-i_start); 19063e158a0SMatt Evans kvm->initrd_gra = INITRD_LOAD_ADDR; 19163e158a0SMatt Evans kvm->initrd_size = p-i_start; 19263e158a0SMatt Evans } else { 19363e158a0SMatt Evans kvm->initrd_size = 0; 19463e158a0SMatt Evans } 19563e158a0SMatt Evans strncpy(kern_cmdline, kernel_cmdline, 2048); 19663e158a0SMatt Evans kern_cmdline[2047] = '\0'; 19763e158a0SMatt Evans 19863e158a0SMatt Evans return true; 19963e158a0SMatt Evans } 20063e158a0SMatt Evans 20163e158a0SMatt Evans bool load_bzimage(struct kvm *kvm, int fd_kernel, 20263e158a0SMatt Evans int fd_initrd, const char *kernel_cmdline, u16 vidmode) 20363e158a0SMatt Evans { 20463e158a0SMatt Evans /* We don't support bzImages. */ 20563e158a0SMatt Evans return false; 20663e158a0SMatt Evans } 20763e158a0SMatt Evans 208d391177aSMatt Evans #define SMT_THREADS 4 209d391177aSMatt Evans 210d391177aSMatt Evans /* 211d391177aSMatt Evans * Set up the FDT for the kernel: This function is currently fairly SPAPR-heavy, 212d391177aSMatt Evans * and whilst most PPC targets will require CPU/memory nodes, others like RTAS 213d391177aSMatt Evans * should eventually be added separately. 214d391177aSMatt Evans */ 21563e158a0SMatt Evans static void setup_fdt(struct kvm *kvm) 21663e158a0SMatt Evans { 217d391177aSMatt Evans uint64_t mem_reg_property[] = { 0, cpu_to_be64(kvm->ram_size) }; 218d391177aSMatt Evans int smp_cpus = kvm->nrcpus; 219d391177aSMatt Evans char hypertas_prop_kvm[] = "hcall-pft\0hcall-term\0" 220d391177aSMatt Evans "hcall-dabr\0hcall-interrupt\0hcall-tce\0hcall-vio\0" 221d391177aSMatt Evans "hcall-splpar\0hcall-bulk"; 222d391177aSMatt Evans int i, j; 223d391177aSMatt Evans char cpu_name[30]; 224d391177aSMatt Evans u8 staging_fdt[FDT_MAX_SIZE]; 225d391177aSMatt Evans struct cpu_info *cpu_info = find_cpu_info(kvm->pvr); 22663e158a0SMatt Evans 227d391177aSMatt Evans /* Generate an appropriate DT at kvm->fdt_gra */ 228d391177aSMatt Evans void *fdt_dest = guest_flat_to_host(kvm, kvm->fdt_gra); 229d391177aSMatt Evans void *fdt = staging_fdt; 230d391177aSMatt Evans 231d391177aSMatt Evans _FDT(fdt_create(fdt, FDT_MAX_SIZE)); 232d391177aSMatt Evans _FDT(fdt_finish_reservemap(fdt)); 233d391177aSMatt Evans 234d391177aSMatt Evans _FDT(fdt_begin_node(fdt, "")); 235d391177aSMatt Evans 236d391177aSMatt Evans _FDT(fdt_property_string(fdt, "device_type", "chrp")); 237d391177aSMatt Evans _FDT(fdt_property_string(fdt, "model", "IBM pSeries (kvmtool)")); 238d391177aSMatt Evans _FDT(fdt_property_cell(fdt, "#address-cells", 0x2)); 239d391177aSMatt Evans _FDT(fdt_property_cell(fdt, "#size-cells", 0x2)); 240d391177aSMatt Evans 241*be76823fSMatt Evans /* RTAS */ 242*be76823fSMatt Evans _FDT(fdt_begin_node(fdt, "rtas")); 243*be76823fSMatt Evans /* This is what the kernel uses to switch 'We're an LPAR'! */ 244*be76823fSMatt Evans _FDT(fdt_property(fdt, "ibm,hypertas-functions", hypertas_prop_kvm, 245*be76823fSMatt Evans sizeof(hypertas_prop_kvm))); 246*be76823fSMatt Evans _FDT(fdt_property_cell(fdt, "linux,rtas-base", kvm->rtas_gra)); 247*be76823fSMatt Evans _FDT(fdt_property_cell(fdt, "linux,rtas-entry", kvm->rtas_gra)); 248*be76823fSMatt Evans _FDT(fdt_property_cell(fdt, "rtas-size", kvm->rtas_size)); 249*be76823fSMatt Evans /* Now add properties for all RTAS tokens: */ 250*be76823fSMatt Evans if (spapr_rtas_fdt_setup(kvm, fdt)) 251*be76823fSMatt Evans die("Couldn't create RTAS FDT properties\n"); 252*be76823fSMatt Evans 253*be76823fSMatt Evans _FDT(fdt_end_node(fdt)); 254*be76823fSMatt Evans 255d391177aSMatt Evans /* /chosen */ 256d391177aSMatt Evans _FDT(fdt_begin_node(fdt, "chosen")); 257d391177aSMatt Evans /* cmdline */ 258d391177aSMatt Evans _FDT(fdt_property_string(fdt, "bootargs", kern_cmdline)); 259d391177aSMatt Evans /* Initrd */ 260d391177aSMatt Evans if (kvm->initrd_size != 0) { 261d391177aSMatt Evans uint32_t ird_st_prop = cpu_to_be32(kvm->initrd_gra); 262d391177aSMatt Evans uint32_t ird_end_prop = cpu_to_be32(kvm->initrd_gra + 263d391177aSMatt Evans kvm->initrd_size); 264d391177aSMatt Evans _FDT(fdt_property(fdt, "linux,initrd-start", 265d391177aSMatt Evans &ird_st_prop, sizeof(ird_st_prop))); 266d391177aSMatt Evans _FDT(fdt_property(fdt, "linux,initrd-end", 267d391177aSMatt Evans &ird_end_prop, sizeof(ird_end_prop))); 268d391177aSMatt Evans } 269d391177aSMatt Evans _FDT(fdt_end_node(fdt)); 270d391177aSMatt Evans 271d391177aSMatt Evans /* 272d391177aSMatt Evans * Memory: We don't alloc. a separate RMA yet. If we ever need to 273d391177aSMatt Evans * (CAP_PPC_RMA == 2) then have one memory node for 0->RMAsize, and 274d391177aSMatt Evans * another RMAsize->endOfMem. 275d391177aSMatt Evans */ 276d391177aSMatt Evans _FDT(fdt_begin_node(fdt, "memory@0")); 277d391177aSMatt Evans _FDT(fdt_property_string(fdt, "device_type", "memory")); 278d391177aSMatt Evans _FDT(fdt_property(fdt, "reg", mem_reg_property, 279d391177aSMatt Evans sizeof(mem_reg_property))); 280d391177aSMatt Evans _FDT(fdt_end_node(fdt)); 281d391177aSMatt Evans 282d391177aSMatt Evans /* CPUs */ 283d391177aSMatt Evans _FDT(fdt_begin_node(fdt, "cpus")); 284d391177aSMatt Evans _FDT(fdt_property_cell(fdt, "#address-cells", 0x1)); 285d391177aSMatt Evans _FDT(fdt_property_cell(fdt, "#size-cells", 0x0)); 286d391177aSMatt Evans 287d391177aSMatt Evans for (i = 0; i < smp_cpus; i += SMT_THREADS) { 288d391177aSMatt Evans int32_t pft_size_prop[] = { 0, HPT_ORDER }; 289d391177aSMatt Evans uint32_t servers_prop[SMT_THREADS]; 290d391177aSMatt Evans uint32_t gservers_prop[SMT_THREADS * 2]; 291d391177aSMatt Evans int threads = (smp_cpus - i) >= SMT_THREADS ? SMT_THREADS : 292d391177aSMatt Evans smp_cpus - i; 293d391177aSMatt Evans 294d391177aSMatt Evans sprintf(cpu_name, "PowerPC,%s@%d", cpu_info->name, i); 295d391177aSMatt Evans _FDT(fdt_begin_node(fdt, cpu_name)); 296d391177aSMatt Evans sprintf(cpu_name, "PowerPC,%s", cpu_info->name); 297d391177aSMatt Evans _FDT(fdt_property_string(fdt, "name", cpu_name)); 298d391177aSMatt Evans _FDT(fdt_property_string(fdt, "device_type", "cpu")); 299d391177aSMatt Evans 300d391177aSMatt Evans _FDT(fdt_property_cell(fdt, "reg", i)); 301d391177aSMatt Evans _FDT(fdt_property_cell(fdt, "cpu-version", kvm->pvr)); 302d391177aSMatt Evans 303d391177aSMatt Evans _FDT(fdt_property_cell(fdt, "dcache-block-size", cpu_info->d_bsize)); 304d391177aSMatt Evans _FDT(fdt_property_cell(fdt, "icache-block-size", cpu_info->i_bsize)); 305d391177aSMatt Evans 306d391177aSMatt Evans _FDT(fdt_property_cell(fdt, "timebase-frequency", cpu_info->tb_freq)); 307d391177aSMatt Evans /* Lies, but safeish lies! */ 308d391177aSMatt Evans _FDT(fdt_property_cell(fdt, "clock-frequency", 0xddbab200)); 309d391177aSMatt Evans 310d391177aSMatt Evans if (cpu_info->slb_size) 311d391177aSMatt Evans _FDT(fdt_property_cell(fdt, "ibm,slb-size", cpu_info->slb_size)); 312d391177aSMatt Evans /* 313d391177aSMatt Evans * HPT size is hardwired; KVM currently fixes it at 16MB but the 314d391177aSMatt Evans * moment that changes we'll need to read it out of the kernel. 315d391177aSMatt Evans */ 316d391177aSMatt Evans _FDT(fdt_property(fdt, "ibm,pft-size", pft_size_prop, 317d391177aSMatt Evans sizeof(pft_size_prop))); 318d391177aSMatt Evans 319d391177aSMatt Evans _FDT(fdt_property_string(fdt, "status", "okay")); 320d391177aSMatt Evans _FDT(fdt_property(fdt, "64-bit", NULL, 0)); 321d391177aSMatt Evans /* A server for each thread in this core */ 322d391177aSMatt Evans for (j = 0; j < SMT_THREADS; j++) { 323d391177aSMatt Evans servers_prop[j] = cpu_to_be32(i+j); 324d391177aSMatt Evans /* 325d391177aSMatt Evans * Hack borrowed from QEMU, direct the group queues back 326d391177aSMatt Evans * to cpu 0: 327d391177aSMatt Evans */ 328d391177aSMatt Evans gservers_prop[j*2] = cpu_to_be32(i+j); 329d391177aSMatt Evans gservers_prop[j*2 + 1] = 0; 330d391177aSMatt Evans } 331d391177aSMatt Evans _FDT(fdt_property(fdt, "ibm,ppc-interrupt-server#s", 332d391177aSMatt Evans servers_prop, threads * sizeof(uint32_t))); 333d391177aSMatt Evans _FDT(fdt_property(fdt, "ibm,ppc-interrupt-gserver#s", 334d391177aSMatt Evans gservers_prop, 335d391177aSMatt Evans threads * 2 * sizeof(uint32_t))); 336d391177aSMatt Evans if (cpu_info->page_sizes_prop) 337d391177aSMatt Evans _FDT(fdt_property(fdt, "ibm,segment-page-sizes", 338d391177aSMatt Evans cpu_info->page_sizes_prop, 339d391177aSMatt Evans cpu_info->page_sizes_prop_len)); 340d391177aSMatt Evans if (cpu_info->segment_sizes_prop) 341d391177aSMatt Evans _FDT(fdt_property(fdt, "ibm,processor-segment-sizes", 342d391177aSMatt Evans cpu_info->segment_sizes_prop, 343d391177aSMatt Evans cpu_info->segment_sizes_prop_len)); 344d391177aSMatt Evans /* VSX / DFP options: */ 345d391177aSMatt Evans if (cpu_info->flags & CPUINFO_FLAG_VMX) 346d391177aSMatt Evans _FDT(fdt_property_cell(fdt, "ibm,vmx", 347d391177aSMatt Evans (cpu_info->flags & 348d391177aSMatt Evans CPUINFO_FLAG_VSX) ? 2 : 1)); 349d391177aSMatt Evans if (cpu_info->flags & CPUINFO_FLAG_DFP) 350d391177aSMatt Evans _FDT(fdt_property_cell(fdt, "ibm,dfp", 0x1)); 351d391177aSMatt Evans _FDT(fdt_end_node(fdt)); 352d391177aSMatt Evans } 353d391177aSMatt Evans _FDT(fdt_end_node(fdt)); 354d391177aSMatt Evans 355d391177aSMatt Evans /* Finalise: */ 356d391177aSMatt Evans _FDT(fdt_end_node(fdt)); /* Root node */ 357d391177aSMatt Evans _FDT(fdt_finish(fdt)); 358d391177aSMatt Evans 359d391177aSMatt Evans _FDT(fdt_open_into(fdt, fdt_dest, FDT_MAX_SIZE)); 360d391177aSMatt Evans _FDT(fdt_add_mem_rsv(fdt_dest, kvm->rtas_gra, kvm->rtas_size)); 361d391177aSMatt Evans _FDT(fdt_pack(fdt_dest)); 36263e158a0SMatt Evans } 36363e158a0SMatt Evans 36463e158a0SMatt Evans /** 36563e158a0SMatt Evans * kvm__arch_setup_firmware 36663e158a0SMatt Evans */ 367f7f9d02bSCyrill Gorcunov int kvm__arch_setup_firmware(struct kvm *kvm) 36863e158a0SMatt Evans { 369*be76823fSMatt Evans /* 370*be76823fSMatt Evans * Set up RTAS stub. All it is is a single hypercall: 371*be76823fSMatt Evans * 0: 7c 64 1b 78 mr r4,r3 372*be76823fSMatt Evans * 4: 3c 60 00 00 lis r3,0 373*be76823fSMatt Evans * 8: 60 63 f0 00 ori r3,r3,61440 374*be76823fSMatt Evans * c: 44 00 00 22 sc 1 375*be76823fSMatt Evans * 10: 4e 80 00 20 blr 376*be76823fSMatt Evans */ 377*be76823fSMatt Evans uint32_t *rtas = guest_flat_to_host(kvm, kvm->rtas_gra); 378*be76823fSMatt Evans 379*be76823fSMatt Evans rtas[0] = 0x7c641b78; 380*be76823fSMatt Evans rtas[1] = 0x3c600000; 381*be76823fSMatt Evans rtas[2] = 0x6063f000; 382*be76823fSMatt Evans rtas[3] = 0x44000022; 383*be76823fSMatt Evans rtas[4] = 0x4e800020; 384*be76823fSMatt Evans kvm->rtas_size = 20; 385*be76823fSMatt Evans 386*be76823fSMatt Evans pr_info("Set up %ld bytes of RTAS at 0x%lx\n", 387*be76823fSMatt Evans kvm->rtas_size, kvm->rtas_gra); 38863e158a0SMatt Evans 38963e158a0SMatt Evans /* Load SLOF */ 39063e158a0SMatt Evans 39163e158a0SMatt Evans /* Init FDT */ 39263e158a0SMatt Evans setup_fdt(kvm); 393f7f9d02bSCyrill Gorcunov 394f7f9d02bSCyrill Gorcunov return 0; 39563e158a0SMatt Evans } 3961add9f73SSasha Levin 3971add9f73SSasha Levin int kvm__arch_free_firmware(struct kvm *kvm) 3981add9f73SSasha Levin { 3991add9f73SSasha Levin return 0; 4001add9f73SSasha Levin } 401