uint64_t sys_getmainvars(HTIFState * htifstate, uint64_t pbuf, uint64_t limit) { #ifdef DEBUG_FRONTEND_RISCV fprintf(stderr, "%s\n", htifstate->kernel_cmdline); #endif void * base = htifstate->main_mem_ram_ptr + (uintptr_t)pbuf; // assume args are bbl + some kernel for now // later, do the right thing const char * arg0 = "bbl"; const char * arg1 = htifstate->kernel_cmdline; #define WORDS_LEN 5 #define START_ARGS (WORDS_LEN*8) uint64_t words[WORDS_LEN] = {2, START_ARGS+pbuf, START_ARGS+pbuf+4, 0, 0}; int i; for (i = 0; i < WORDS_LEN; i++) { stq_p((void*)(base+i*8), words[i]); } for (i = 0; i < 4; i++) { stb_p((void*)(base + START_ARGS + i), arg0[i]); } for (i = 0; i < strlen(arg1)+1; i++) { stb_p((void*)(base + START_ARGS+4 + i), arg1[i]); } // currently no support for > 2 args return 0; }
void glue(address_space_stb, SUFFIX)(ARG1_DECL, hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result) { uint8_t *ptr; MemoryRegion *mr; hwaddr l = 1; hwaddr addr1; MemTxResult r; bool release_lock = false; RCU_READ_LOCK(); mr = TRANSLATE(addr, &addr1, &l, true); if (!IS_DIRECT(mr, true)) { release_lock |= prepare_mmio_access(mr); r = memory_region_dispatch_write(mr, addr1, val, 1, attrs); } else { /* RAM case */ ptr = MAP_RAM(mr, addr1); stb_p(ptr, val); INVALIDATE(mr, addr1, 1); r = MEMTX_OK; } if (result) { *result = r; } if (release_lock) { qemu_mutex_unlock_iothread(); } RCU_READ_UNLOCK(); }
static void virtio_blk_req_complete(VirtIOBlockReq *req, int status) { VirtIOBlock *s = req->dev; trace_virtio_blk_req_complete(req, status); stb_p(&req->in->status, status); virtqueue_push(s->vq, &req->elem, req->qiov.size + sizeof(*req->in)); virtio_notify(&s->vdev, s->vq); }
static void virtio_blk_complete_request(VirtIOBlockReq *req, unsigned char status) { VirtIOBlock *s = req->dev; VirtIODevice *vdev = VIRTIO_DEVICE(s); trace_virtio_blk_req_complete(req, status); stb_p(&req->in->status, status); virtqueue_push(s->vq, &req->elem, req->in_len); virtio_notify(vdev, s->vq); }
static void virtio_crypto_req_complete(VirtIOCryptoReq *req, uint8_t status) { VirtIOCrypto *vcrypto = req->vcrypto; VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto); if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) { virtio_crypto_sym_input_data_helper(vdev, req, status, req->u.sym_op_info); } stb_p(&req->in->status, status); virtqueue_push(req->vq, &req->elem, req->in_len); virtio_notify(vdev, req->vq); }
static void complete_request_vring(VirtIOBlockReq *req, unsigned char status) { VirtIOBlockDataPlane *s = req->dev->dataplane; stb_p(&req->in->status, status); vring_push(s->vdev, &req->dev->dataplane->vring, &req->elem, req->in_len); /* Suppress notification to guest by BH and its scheduled * flag because requests are completed as a batch after io * plug & unplug is introduced, and the BH can still be * executed in dataplane aio context even after it is * stopped, so needn't worry about notification loss with BH. */ qemu_bh_schedule(s->bh); }
static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status) { VirtIOBlock *s = req->dev; VirtIODevice *vdev = VIRTIO_DEVICE(s); trace_virtio_blk_req_complete(vdev, req, status); stb_p(&req->in->status, status); virtqueue_push(req->vq, &req->elem, req->in_len); if (s->dataplane_started && !s->dataplane_disabled) { virtio_blk_data_plane_notify(s->dataplane, req->vq); } else { virtio_notify(vdev, req->vq); } }
static void spin_write(void *opaque, hwaddr addr, uint64_t value, unsigned len) { SpinState *s = opaque; int env_idx = addr / sizeof(SpinInfo); CPUPPCState *env; SpinInfo *curspin = &s->spin[env_idx]; uint8_t *curspin_p = (uint8_t*)curspin; for (env = first_cpu; env != NULL; env = env->next_cpu) { if (env->cpu_index == env_idx) { break; } } if (!env) { /* Unknown CPU */ return; } if (!env->cpu_index) { /* primary CPU doesn't spin */ return; } curspin_p = &curspin_p[addr % sizeof(SpinInfo)]; switch (len) { case 1: stb_p(curspin_p, value); break; case 2: stw_p(curspin_p, value); break; case 4: stl_p(curspin_p, value); break; } if (!(ldq_p(&curspin->addr) & 1)) { /* run CPU */ SpinKick kick = { .cpu = ppc_env_get_cpu(env), .spin = curspin, }; run_on_cpu(CPU(kick.cpu), spin_kick, &kick); }
static void spin_write(void *opaque, hwaddr addr, uint64_t value, unsigned len) { SpinState *s = opaque; int env_idx = addr / sizeof(SpinInfo); CPUState *cpu; SpinInfo *curspin = &s->spin[env_idx]; uint8_t *curspin_p = (uint8_t*)curspin; cpu = qemu_get_cpu(env_idx); if (cpu == NULL) { /* Unknown CPU */ return; } if (cpu->cpu_index == 0) { /* primary CPU doesn't spin */ return; } curspin_p = &curspin_p[addr % sizeof(SpinInfo)]; switch (len) { case 1: stb_p(curspin_p, value); break; case 2: stw_p(curspin_p, value); break; case 4: stl_p(curspin_p, value); break; } if (!(ldq_p(&curspin->addr) & 1)) { /* run CPU */ SpinKick kick = { .cpu = POWERPC_CPU(cpu), .spin = curspin, }; run_on_cpu(cpu, spin_kick, &kick); }
uint64_t sys_pread(HTIFState *htifstate, uint64_t fd, uint64_t pbuf, uint64_t len, uint64_t off) { #ifdef DEBUG_FRONTEND_RISCV fprintf(stderr, "read fd: %ld, len: %ld, off: %ld\n", fd, len, off); #endif if (fd != 3) { fprintf(stderr, "INVALID pread fd: %ld. only 3 allowed\n", fd); exit(1); } char * buf = malloc(sizeof(char)*len); size_t bytes_read = pread(real_kernelfd, buf, len, off); void * base = htifstate->main_mem_ram_ptr + (uintptr_t)pbuf; int i; for (i = 0; i < bytes_read; i++) { stb_p((void*)(base + i), buf[i]); } free(buf); return bytes_read; }
static void riscv_sifive_board_init(MachineState *args) { ram_addr_t ram_size = args->ram_size; const char *cpu_model = args->cpu_model; const char *kernel_filename = args->kernel_filename; const char *kernel_cmdline = args->kernel_cmdline; const char *initrd_filename = args->initrd_filename; MemoryRegion *system_memory = get_system_memory(); MemoryRegion *main_mem = g_new(MemoryRegion, 1); RISCVCPU *cpu; CPURISCVState *env; int i; DeviceState *dev = qdev_create(NULL, TYPE_RISCV_SIFIVE_BOARD); object_property_set_bool(OBJECT(dev), true, "realized", NULL); /* Make sure the first 3 serial ports are associated with a device. */ for (i = 0; i < 3; i++) { if (!serial_hds[i]) { char label[32]; snprintf(label, sizeof(label), "serial%d", i); serial_hds[i] = qemu_chr_new(label, "null", NULL); } } /* init CPUs */ if (cpu_model == NULL) { cpu_model = "any"; } for (i = 0; i < smp_cpus; i++) { cpu = cpu_riscv_init(cpu_model); if (cpu == NULL) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } env = &cpu->env; /* Init internal devices */ cpu_riscv_irq_init_cpu(env); cpu_riscv_clock_init(env); qemu_register_reset(main_cpu_reset, cpu); } cpu = RISCV_CPU(first_cpu); env = &cpu->env; /* register system main memory (actual RAM) */ memory_region_init_ram(main_mem, NULL, "riscv_sifive_board.ram", 2147483648ll + ram_size, &error_fatal); /* for phys mem size check in page table walk */ env->memsize = ram_size; vmstate_register_ram_global(main_mem); memory_region_add_subregion(system_memory, 0x0, main_mem); if (kernel_filename) { loaderparams.ram_size = ram_size; loaderparams.kernel_filename = kernel_filename; loaderparams.kernel_cmdline = kernel_cmdline; loaderparams.initrd_filename = initrd_filename; load_kernel(); } uint32_t reset_vec[8] = { 0x297 + 0x80000000 - 0x1000, /* reset vector */ 0x00028067, /* jump to DRAM_BASE */ 0x00000000, /* reserved */ 0x0, /* config string pointer */ 0, 0, 0, 0 /* trap vector */ }; reset_vec[3] = 0x1000 + sizeof(reset_vec); /* config string pointer */ /* part one of config string - before memory size specified */ const char *config_string1 = "platform {\n" " vendor ucb;\n" " arch spike;\n" "};\n" "plic { \n" " interface \"plic\"; \n" " ndevs 2; \n" " priority { mem { 0x60000000 0x60000fff; }; }; \n" " pending { mem { 0x60001000 0x6000107f; }; }; \n" " 0 { \n" " 0 { \n" " m { \n" " ie { mem { 0x60002000 0x6000207f; }; }; \n" " ctl { mem { 0x60200000 0x60200007; }; }; \n" " }; \n" " s { \n" " ie { mem { 0x60002080 0x600020ff; }; }; \n" " ctl { mem { 0x60201000 0x60201007; }; }; \n" " }; \n" " }; \n" " }; \n" "}; \n" "rtc {\n" " addr 0x" "40000000" ";\n" "};\n" "uart {\n" " addr 0x40002000;\n" "};\n" "ram {\n" " 0 {\n" " addr 0x" "80000000" ";\n" " size 0x"; /* part two of config string - after memory size specified */ const char *config_string2 = ";\n" " };\n" "};\n" "core {\n" " 0" " {\n" " " "0 {\n" " isa " "rv64imafd" ";\n" " timecmp 0x" "40000008" ";\n" " ipi 0x" "40001000" ";\n" " };\n" " };\n" "};\n"; /* build config string with supplied memory size */ uint64_t rsz = ram_size; char *ramsize_as_hex_str = malloc(17); sprintf(ramsize_as_hex_str, "%016" PRIx64, rsz); char *config_string = malloc(strlen(config_string1) + strlen(ramsize_as_hex_str) + strlen(config_string2) + 1); config_string[0] = 0; strcat(config_string, config_string1); strcat(config_string, ramsize_as_hex_str); strcat(config_string, config_string2); /* copy in the reset vec and configstring */ int q; for (q = 0; q < sizeof(reset_vec) / sizeof(reset_vec[0]); q++) { stl_p(memory_region_get_ram_ptr(main_mem) + 0x1000 + q * 4, reset_vec[q]); } int confstrlen = strlen(config_string); for (q = 0; q < confstrlen; q++) { stb_p(memory_region_get_ram_ptr(main_mem) + reset_vec[3] + q, config_string[q]); } sifive_uart_create(0x40002000, serial_hds[0]); /* timer device at 0x40000000, as specified in the config string above */ timer_mm_init(system_memory, 0x40000000, env); /* TODO: VIRTIO */ }