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" 20*7295767dSMatt 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 4263e158a0SMatt Evans static char kern_cmdline[2048]; 4363e158a0SMatt Evans 4463e158a0SMatt Evans struct kvm_ext kvm_req_ext[] = { 4563e158a0SMatt Evans { 0, 0 } 4663e158a0SMatt Evans }; 4763e158a0SMatt Evans 48d391177aSMatt Evans static uint32_t mfpvr(void) 49d391177aSMatt Evans { 50d391177aSMatt Evans uint32_t r; 51d391177aSMatt Evans asm volatile ("mfpvr %0" : "=r"(r)); 52d391177aSMatt Evans return r; 53d391177aSMatt Evans } 54d391177aSMatt Evans 5563e158a0SMatt Evans bool kvm__arch_cpu_supports_vm(void) 5663e158a0SMatt Evans { 5763e158a0SMatt Evans return true; 5863e158a0SMatt Evans } 5963e158a0SMatt Evans 6063e158a0SMatt Evans void kvm__init_ram(struct kvm *kvm) 6163e158a0SMatt Evans { 6263e158a0SMatt Evans u64 phys_start, phys_size; 6363e158a0SMatt Evans void *host_mem; 6463e158a0SMatt Evans 6563e158a0SMatt Evans phys_start = 0; 6663e158a0SMatt Evans phys_size = kvm->ram_size; 6763e158a0SMatt Evans host_mem = kvm->ram_start; 6863e158a0SMatt Evans 6963e158a0SMatt Evans /* 7063e158a0SMatt Evans * We put MMIO at PPC_MMIO_START, high up. Make sure that this doesn't 7163e158a0SMatt Evans * crash into the end of RAM -- on PPC64 at least, this is so high 7263e158a0SMatt Evans * (63TB!) that this is unlikely. 7363e158a0SMatt Evans */ 7463e158a0SMatt Evans if (phys_size >= PPC_MMIO_START) 7563e158a0SMatt Evans die("Too much memory (%lld, what a nice problem): " 7663e158a0SMatt Evans "overlaps MMIO!\n", 7763e158a0SMatt Evans phys_size); 7863e158a0SMatt Evans 7963e158a0SMatt Evans kvm__register_mem(kvm, phys_start, phys_size, host_mem); 8063e158a0SMatt Evans } 8163e158a0SMatt Evans 8263e158a0SMatt Evans void kvm__arch_set_cmdline(char *cmdline, bool video) 8363e158a0SMatt Evans { 8463e158a0SMatt Evans /* We don't need anything unusual in here. */ 8563e158a0SMatt Evans } 8663e158a0SMatt Evans 8763e158a0SMatt Evans /* Architecture-specific KVM init */ 887eff9f49SWanlong Gao void kvm__arch_init(struct kvm *kvm, const char *hugetlbfs_path, u64 ram_size) 8963e158a0SMatt Evans { 9063e158a0SMatt Evans int cap_ppc_rma; 91df129a0aSMatt Evans unsigned long hpt; 9263e158a0SMatt Evans 9363e158a0SMatt Evans kvm->ram_size = ram_size; 9463e158a0SMatt Evans 9563e158a0SMatt Evans /* 96df129a0aSMatt Evans * Currently, HV-mode PPC64 SPAPR requires that we map from hugetlfs. 97df129a0aSMatt Evans * Allow a 'default' option to assist. 98df129a0aSMatt Evans * PR-mode does not require this. 9963e158a0SMatt Evans */ 100df129a0aSMatt Evans if (hugetlbfs_path) { 101df129a0aSMatt Evans if (!strcmp(hugetlbfs_path, "default")) 10263e158a0SMatt Evans hugetlbfs_path = HUGETLBFS_PATH; 10363e158a0SMatt Evans kvm->ram_start = mmap_hugetlbfs(hugetlbfs_path, kvm->ram_size); 104df129a0aSMatt Evans } else { 105df129a0aSMatt Evans kvm->ram_start = mmap(0, kvm->ram_size, PROT_READ | PROT_WRITE, 106df129a0aSMatt Evans MAP_ANON | MAP_PRIVATE, 107df129a0aSMatt Evans -1, 0); 108df129a0aSMatt Evans } 10963e158a0SMatt Evans if (kvm->ram_start == MAP_FAILED) 11063e158a0SMatt Evans die("Couldn't map %lld bytes for RAM (%d)\n", 11163e158a0SMatt Evans kvm->ram_size, errno); 11263e158a0SMatt Evans 11363e158a0SMatt Evans /* FDT goes at top of memory, RTAS just below */ 11463e158a0SMatt Evans kvm->fdt_gra = kvm->ram_size - FDT_MAX_SIZE; 11563e158a0SMatt Evans /* FIXME: Not all PPC systems have RTAS */ 11663e158a0SMatt Evans kvm->rtas_gra = kvm->fdt_gra - RTAS_MAX_SIZE; 11763e158a0SMatt Evans madvise(kvm->ram_start, kvm->ram_size, MADV_MERGEABLE); 11863e158a0SMatt Evans 119df129a0aSMatt Evans /* FIXME: SPAPR-PR specific; allocate a guest HPT. */ 120df129a0aSMatt Evans if (posix_memalign((void **)&hpt, (1<<HPT_ORDER), (1<<HPT_ORDER))) 121df129a0aSMatt Evans die("Can't allocate %d bytes for HPT\n", (1<<HPT_ORDER)); 122df129a0aSMatt Evans 123df129a0aSMatt Evans kvm->sdr1 = ((hpt + 0x3ffffULL) & ~0x3ffffULL) | (HPT_ORDER-18); 124df129a0aSMatt Evans 125d391177aSMatt Evans kvm->pvr = mfpvr(); 126d391177aSMatt Evans 12763e158a0SMatt Evans /* FIXME: This is book3s-specific */ 12863e158a0SMatt Evans cap_ppc_rma = ioctl(kvm->sys_fd, KVM_CHECK_EXTENSION, KVM_CAP_PPC_RMA); 12963e158a0SMatt Evans if (cap_ppc_rma == 2) 13063e158a0SMatt Evans die("Need contiguous RMA allocation on this hardware, " 13163e158a0SMatt Evans "which is not yet supported."); 132be76823fSMatt Evans 133be76823fSMatt Evans /* Do these before FDT setup, IRQ setup, etc. */ 134be76823fSMatt Evans /* FIXME: SPAPR-specific */ 135be76823fSMatt Evans hypercall_init(); 136be76823fSMatt Evans register_core_rtas(); 137*7295767dSMatt Evans /* Now that hypercalls are initialised, register a couple for the console: */ 138*7295767dSMatt Evans spapr_hvcons_init(); 13963e158a0SMatt Evans } 14063e158a0SMatt Evans 141e56e2de7SLai Jiangshan void kvm__arch_delete_ram(struct kvm *kvm) 142e56e2de7SLai Jiangshan { 143e56e2de7SLai Jiangshan munmap(kvm->ram_start, kvm->ram_size); 144e56e2de7SLai Jiangshan } 145e56e2de7SLai Jiangshan 14663e158a0SMatt Evans void kvm__irq_line(struct kvm *kvm, int irq, int level) 14763e158a0SMatt Evans { 14863e158a0SMatt Evans fprintf(stderr, "irq_line(%d, %d)\n", irq, level); 14963e158a0SMatt Evans } 15063e158a0SMatt Evans 15163e158a0SMatt Evans void kvm__irq_trigger(struct kvm *kvm, int irq) 15263e158a0SMatt Evans { 15363e158a0SMatt Evans kvm__irq_line(kvm, irq, 1); 15463e158a0SMatt Evans kvm__irq_line(kvm, irq, 0); 15563e158a0SMatt Evans } 15663e158a0SMatt Evans 157*7295767dSMatt Evans void kvm__arch_periodic_poll(struct kvm *kvm) 158*7295767dSMatt Evans { 159*7295767dSMatt Evans /* FIXME: Should register callbacks to platform-specific polls */ 160*7295767dSMatt Evans spapr_hvcons_poll(kvm); 161*7295767dSMatt Evans } 162*7295767dSMatt Evans 16363e158a0SMatt Evans int load_flat_binary(struct kvm *kvm, int fd_kernel, int fd_initrd, const char *kernel_cmdline) 16463e158a0SMatt Evans { 16563e158a0SMatt Evans void *p; 16663e158a0SMatt Evans void *k_start; 16763e158a0SMatt Evans void *i_start; 16863e158a0SMatt Evans int nr; 16963e158a0SMatt Evans 17063e158a0SMatt Evans if (lseek(fd_kernel, 0, SEEK_SET) < 0) 17163e158a0SMatt Evans die_perror("lseek"); 17263e158a0SMatt Evans 17363e158a0SMatt Evans p = k_start = guest_flat_to_host(kvm, KERNEL_LOAD_ADDR); 17463e158a0SMatt Evans 17563e158a0SMatt Evans while ((nr = read(fd_kernel, p, 65536)) > 0) 17663e158a0SMatt Evans p += nr; 17763e158a0SMatt Evans 17863e158a0SMatt Evans pr_info("Loaded kernel to 0x%x (%ld bytes)", KERNEL_LOAD_ADDR, p-k_start); 17963e158a0SMatt Evans 18063e158a0SMatt Evans if (fd_initrd != -1) { 18163e158a0SMatt Evans if (lseek(fd_initrd, 0, SEEK_SET) < 0) 18263e158a0SMatt Evans die_perror("lseek"); 18363e158a0SMatt Evans 18463e158a0SMatt Evans if (p-k_start > INITRD_LOAD_ADDR) 18563e158a0SMatt Evans die("Kernel overlaps initrd!"); 18663e158a0SMatt Evans 18763e158a0SMatt Evans /* Round up kernel size to 8byte alignment, and load initrd right after. */ 18863e158a0SMatt Evans i_start = p = guest_flat_to_host(kvm, INITRD_LOAD_ADDR); 18963e158a0SMatt Evans 19063e158a0SMatt Evans while (((nr = read(fd_initrd, p, 65536)) > 0) && 19163e158a0SMatt Evans p < (kvm->ram_start + kvm->ram_size)) 19263e158a0SMatt Evans p += nr; 19363e158a0SMatt Evans 19463e158a0SMatt Evans if (p >= (kvm->ram_start + kvm->ram_size)) 19563e158a0SMatt Evans die("initrd too big to contain in guest RAM.\n"); 19663e158a0SMatt Evans 19763e158a0SMatt Evans pr_info("Loaded initrd to 0x%x (%ld bytes)", 19863e158a0SMatt Evans INITRD_LOAD_ADDR, p-i_start); 19963e158a0SMatt Evans kvm->initrd_gra = INITRD_LOAD_ADDR; 20063e158a0SMatt Evans kvm->initrd_size = p-i_start; 20163e158a0SMatt Evans } else { 20263e158a0SMatt Evans kvm->initrd_size = 0; 20363e158a0SMatt Evans } 20463e158a0SMatt Evans strncpy(kern_cmdline, kernel_cmdline, 2048); 20563e158a0SMatt Evans kern_cmdline[2047] = '\0'; 20663e158a0SMatt Evans 20763e158a0SMatt Evans return true; 20863e158a0SMatt Evans } 20963e158a0SMatt Evans 21063e158a0SMatt Evans bool load_bzimage(struct kvm *kvm, int fd_kernel, 21163e158a0SMatt Evans int fd_initrd, const char *kernel_cmdline, u16 vidmode) 21263e158a0SMatt Evans { 21363e158a0SMatt Evans /* We don't support bzImages. */ 21463e158a0SMatt Evans return false; 21563e158a0SMatt Evans } 21663e158a0SMatt Evans 217d391177aSMatt Evans #define SMT_THREADS 4 218d391177aSMatt Evans 219d391177aSMatt Evans /* 220d391177aSMatt Evans * Set up the FDT for the kernel: This function is currently fairly SPAPR-heavy, 221d391177aSMatt Evans * and whilst most PPC targets will require CPU/memory nodes, others like RTAS 222d391177aSMatt Evans * should eventually be added separately. 223d391177aSMatt Evans */ 22463e158a0SMatt Evans static void setup_fdt(struct kvm *kvm) 22563e158a0SMatt Evans { 226d391177aSMatt Evans uint64_t mem_reg_property[] = { 0, cpu_to_be64(kvm->ram_size) }; 227d391177aSMatt Evans int smp_cpus = kvm->nrcpus; 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 } 278*7295767dSMatt Evans 279*7295767dSMatt Evans /* 280*7295767dSMatt Evans * stdout-path: This is assuming we're using the HV console. Also, the 281*7295767dSMatt Evans * address is hardwired until we do a VIO bus. 282*7295767dSMatt Evans */ 283*7295767dSMatt Evans _FDT(fdt_property_string(fdt, "linux,stdout-path", 284*7295767dSMatt 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*7295767dSMatt Evans /* 372*7295767dSMatt Evans * VIO: See comment in linux,stdout-path; we don't yet represent a VIO 373*7295767dSMatt Evans * bus/address allocation so addresses are hardwired here. 374*7295767dSMatt Evans */ 375*7295767dSMatt Evans _FDT(fdt_begin_node(fdt, "vdevice")); 376*7295767dSMatt Evans _FDT(fdt_property_cell(fdt, "#address-cells", 0x1)); 377*7295767dSMatt Evans _FDT(fdt_property_cell(fdt, "#size-cells", 0x0)); 378*7295767dSMatt Evans _FDT(fdt_property_string(fdt, "device_type", "vdevice")); 379*7295767dSMatt Evans _FDT(fdt_property_string(fdt, "compatible", "IBM,vdevice")); 380*7295767dSMatt Evans _FDT(fdt_begin_node(fdt, "vty@30000000")); 381*7295767dSMatt Evans _FDT(fdt_property_string(fdt, "name", "vty")); 382*7295767dSMatt Evans _FDT(fdt_property_string(fdt, "device_type", "serial")); 383*7295767dSMatt Evans _FDT(fdt_property_string(fdt, "compatible", "hvterm1")); 384*7295767dSMatt Evans _FDT(fdt_property_cell(fdt, "reg", 0x30000000)); 385*7295767dSMatt Evans _FDT(fdt_end_node(fdt)); 386*7295767dSMatt Evans _FDT(fdt_end_node(fdt)); 387*7295767dSMatt Evans 388d391177aSMatt Evans /* Finalise: */ 389d391177aSMatt Evans _FDT(fdt_end_node(fdt)); /* Root node */ 390d391177aSMatt Evans _FDT(fdt_finish(fdt)); 391d391177aSMatt Evans 392d391177aSMatt Evans _FDT(fdt_open_into(fdt, fdt_dest, FDT_MAX_SIZE)); 393d391177aSMatt Evans _FDT(fdt_add_mem_rsv(fdt_dest, kvm->rtas_gra, kvm->rtas_size)); 394d391177aSMatt Evans _FDT(fdt_pack(fdt_dest)); 39563e158a0SMatt Evans } 39663e158a0SMatt Evans 39763e158a0SMatt Evans /** 39863e158a0SMatt Evans * kvm__arch_setup_firmware 39963e158a0SMatt Evans */ 400f7f9d02bSCyrill Gorcunov int kvm__arch_setup_firmware(struct kvm *kvm) 40163e158a0SMatt Evans { 402be76823fSMatt Evans /* 403be76823fSMatt Evans * Set up RTAS stub. All it is is a single hypercall: 404be76823fSMatt Evans * 0: 7c 64 1b 78 mr r4,r3 405be76823fSMatt Evans * 4: 3c 60 00 00 lis r3,0 406be76823fSMatt Evans * 8: 60 63 f0 00 ori r3,r3,61440 407be76823fSMatt Evans * c: 44 00 00 22 sc 1 408be76823fSMatt Evans * 10: 4e 80 00 20 blr 409be76823fSMatt Evans */ 410be76823fSMatt Evans uint32_t *rtas = guest_flat_to_host(kvm, kvm->rtas_gra); 411be76823fSMatt Evans 412be76823fSMatt Evans rtas[0] = 0x7c641b78; 413be76823fSMatt Evans rtas[1] = 0x3c600000; 414be76823fSMatt Evans rtas[2] = 0x6063f000; 415be76823fSMatt Evans rtas[3] = 0x44000022; 416be76823fSMatt Evans rtas[4] = 0x4e800020; 417be76823fSMatt Evans kvm->rtas_size = 20; 418be76823fSMatt Evans 419be76823fSMatt Evans pr_info("Set up %ld bytes of RTAS at 0x%lx\n", 420be76823fSMatt Evans kvm->rtas_size, kvm->rtas_gra); 42163e158a0SMatt Evans 42263e158a0SMatt Evans /* Load SLOF */ 42363e158a0SMatt Evans 42463e158a0SMatt Evans /* Init FDT */ 42563e158a0SMatt Evans setup_fdt(kvm); 426f7f9d02bSCyrill Gorcunov 427f7f9d02bSCyrill Gorcunov return 0; 42863e158a0SMatt Evans } 4291add9f73SSasha Levin 4301add9f73SSasha Levin int kvm__arch_free_firmware(struct kvm *kvm) 4311add9f73SSasha Levin { 4321add9f73SSasha Levin return 0; 4331add9f73SSasha Levin } 434