status_t virtio_gpu_init(struct virtio_device *dev, uint32_t host_features) { LTRACEF("dev %p, host_features 0x%x\n", dev, host_features); /* allocate a new gpu device */ struct virtio_gpu_dev *gdev = malloc(sizeof(struct virtio_gpu_dev)); if (!gdev) return ERR_NO_MEMORY; mutex_init(&gdev->lock); event_init(&gdev->io_event, false, EVENT_FLAG_AUTOUNSIGNAL); event_init(&gdev->flush_event, false, EVENT_FLAG_AUTOUNSIGNAL); gdev->dev = dev; dev->priv = gdev; gdev->pmode_id = -1; gdev->next_resource_id = 1; /* allocate memory for a gpu request */ #if WITH_KERNEL_VM gdev->gpu_request = pmm_alloc_kpage(); gdev->gpu_request_phys = vaddr_to_paddr(gdev->gpu_request); #else gdev->gpu_request = malloc(sizeof(struct virtio_gpu_resp_display_info)); // XXX get size better gdev->gpu_request_phys = (paddr_t)gdev->gpu_request; #endif /* make sure the device is reset */ virtio_reset_device(dev); volatile struct virtio_gpu_config *config = (struct virtio_gpu_config *)dev->config_ptr; dump_gpu_config(config); /* ack and set the driver status bit */ virtio_status_acknowledge_driver(dev); // XXX check features bits and ack/nak them /* allocate a virtio ring */ virtio_alloc_ring(dev, 0, 16); /* set our irq handler */ dev->irq_driver_callback = &virtio_gpu_irq_driver_callback; dev->config_change_callback = &virtio_gpu_config_change_callback; /* set DRIVER_OK */ virtio_status_driver_ok(dev); /* save the main device we've found */ the_gdev = gdev; printf("found virtio gpu device\n"); return NO_ERROR; }
status_t arch_mmu_init_aspace(arch_aspace_t *aspace, vaddr_t base, size_t size, uint flags) { LTRACEF("aspace %p, base 0x%lx, size 0x%zx, flags 0x%x\n", aspace, base, size, flags); DEBUG_ASSERT(aspace); /* validate that the base + size is sane and doesn't wrap */ DEBUG_ASSERT(size > PAGE_SIZE); DEBUG_ASSERT(base + size - 1 > base); list_initialize(&aspace->pt_page_list); if (flags & ARCH_ASPACE_FLAG_KERNEL) { aspace->base = base; aspace->size = size; aspace->tt_virt = arm_kernel_translation_table; aspace->tt_phys = vaddr_to_paddr(aspace->tt_virt); } else { // XXX at the moment we can only really deal with 1GB user space, and thus // needing only a single page for the top level translation table DEBUG_ASSERT(base < GB && (base + size) <= GB); aspace->base = base; aspace->size = size; uint32_t *va = pmm_alloc_kpages(1, &aspace->pt_page_list); if (!va) return ERR_NO_MEMORY; aspace->tt_virt = va; aspace->tt_phys = vaddr_to_paddr(aspace->tt_virt); } LTRACEF("tt_phys 0x%lx tt_virt %p\n", aspace->tt_phys, aspace->tt_virt); return NO_ERROR; }
static status_t attach_backing(struct virtio_gpu_dev *gdev, uint32_t resource_id, void *ptr, size_t buf_len) { status_t err; LTRACEF("gdev %p, resource_id %u, ptr %p, buf_len %zu\n", gdev, resource_id, ptr, buf_len); DEBUG_ASSERT(gdev); DEBUG_ASSERT(ptr); /* grab a lock to keep this single message at a time */ mutex_acquire(&gdev->lock); /* construct the request */ struct { struct virtio_gpu_resource_attach_backing req; struct virtio_gpu_mem_entry mem; } req; memset(&req, 0, sizeof(req)); req.req.hdr.type = VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING; req.req.resource_id = resource_id; req.req.nr_entries = 1; paddr_t pa; pa = vaddr_to_paddr(ptr); req.mem.addr = pa; req.mem.length = buf_len; /* send the command and get a response */ struct virtio_gpu_ctrl_hdr *res; err = send_command_response(gdev, &req, sizeof(req), (void **)&res, sizeof(*res)); DEBUG_ASSERT(err == NO_ERROR); /* see if we got a valid response */ LTRACEF("response type 0x%x\n", res->type); err = (res->type == VIRTIO_GPU_RESP_OK_NODATA) ? NO_ERROR : ERR_NO_MEMORY; /* release the lock */ mutex_release(&gdev->lock); return err; }
static void test_identity_zone(void) { uint32_t i; uint32_t count; paddr_t paddr; vm_as_t* as; as = vm_get_kernel_as(); count = phys_get_mem_size(); for (i = 0; i < count; ++i) { paddr = vaddr_to_paddr(as, (vaddr_t)i); if (paddr != NULL) { if (*(uint8_t*)paddr != ((uint8_t*)as->identity)[i]) serial_printl("[!] error @ 0x%x\n", i); } } }
static int cmd_display_mem(int argc, const cmd_args *argv, uint32_t flags) { /* save the last address and len so we can continue where we left off */ static unsigned long address; static size_t len; if (argc < 3 && len == 0) { printf("not enough arguments\n"); printf("%s [-l] [-b] [address] [length]\n", argv[0].str); return -1; } int size; if (strcmp(argv[0].str, "dw") == 0) { size = 4; } else if (strcmp(argv[0].str, "dh") == 0) { size = 2; } else { size = 1; } uint byte_order = BYTE_ORDER; int argindex = 1; bool read_address = false; while (argc > argindex) { if (!strcmp(argv[argindex].str, "-l")) { byte_order = LITTLE_ENDIAN; } else if (!strcmp(argv[argindex].str, "-b")) { byte_order = BIG_ENDIAN; } else if (!read_address) { address = argv[argindex].u; read_address = true; } else { len = argv[argindex].u; } argindex++; } unsigned long stop = address + len; int count = 0; if ((address & (size - 1)) != 0) { printf("unaligned address, cannot display\n"); return -1; } /* preflight the start address to see if it's mapped */ if (vaddr_to_paddr((void *)address) == 0) { printf("ERROR: address 0x%lx is unmapped\n", address); return -1; } for ( ; address < stop; address += size) { if (count == 0) printf("0x%08lx: ", address); switch (size) { case 4: { uint32_t val = (byte_order != BYTE_ORDER) ? SWAP_32(*(uint32_t *)address) : *(uint32_t *)address; printf("%08x ", val); break; } case 2: { uint16_t val = (byte_order != BYTE_ORDER) ? SWAP_16(*(uint16_t *)address) : *(uint16_t *)address; printf("%04hx ", val); break; } case 1: printf("%02hhx ", *(uint8_t *)address); break; } count += size; if (count == 16) { printf("\n"); count = 0; } } if (count != 0) printf("\n"); return 0; }
// return NULL for success, error string for failure int lkb_handle_command(lkb_t *lkb, const char *cmd, const char *arg, size_t len, const char **result) { *result = NULL; struct lkb_command *lcmd; for (lcmd = lkb_cmd_list; lcmd; lcmd = lcmd->next) { if (!strcmp(lcmd->name, cmd)) { *result = lcmd->handler(lkb, arg, len, lcmd->cookie); return 0; } } if (!strcmp(cmd, "flash") || !strcmp(cmd, "erase")) { struct ptable_entry entry; bdev_t *bdev; if (ptable_find(arg, &entry) < 0) { size_t plen = len; /* doesn't exist, make one */ if (ptable_add(arg, plen, 0) < 0) { *result = "error creating partition"; return -1; } if (ptable_find(arg, &entry) < 0) { *result = "couldn't find partition after creating it"; return -1; } } if (len > entry.length) { *result = "partition too small"; return -1; } if (!(bdev = ptable_get_device())) { *result = "ptable_get_device failed"; return -1; } printf("lkboot: erasing partition of size %llu\n", entry.length); if (bio_erase(bdev, entry.offset, entry.length) != (ssize_t)entry.length) { *result = "bio_erase failed"; return -1; } if (!strcmp(cmd, "flash")) { printf("lkboot: writing to partition\n"); void *buf = malloc(bdev->block_size); if (!buf) { *result = "memory allocation failed"; return -1; } size_t pos = 0; while (pos < len) { size_t toread = MIN(len - pos, bdev->block_size); LTRACEF("offset %zu, toread %zu\n", pos, toread); if (lkb_read(lkb, buf, toread)) { *result = "io error"; free(buf); return -1; } if (bio_write(bdev, buf, entry.offset + pos, toread) != (ssize_t)toread) { *result = "bio_write failed"; free(buf); return -1; } pos += toread; } free(buf); } } else if (!strcmp(cmd, "remove")) { if (ptable_remove(arg) < 0) { *result = "remove failed"; return -1; } } else if (!strcmp(cmd, "fpga")) { #if PLATFORM_ZYNQ void *buf = malloc(len); if (!buf) { *result = "error allocating buffer"; return -1; } /* translate to physical address */ paddr_t pa = vaddr_to_paddr(buf); if (pa == 0) { *result = "error allocating buffer"; free(buf); return -1; } if (lkb_read(lkb, buf, len)) { *result = "io error"; free(buf); return -1; } /* make sure the cache is flushed for this buffer for DMA coherency purposes */ arch_clean_cache_range((vaddr_t)buf, len); /* program the fpga */ zynq_reset_fpga(); zynq_program_fpga(pa, len); free(buf); #else *result = "no fpga"; return -1; #endif } else if (!strcmp(cmd, "boot")) { return do_boot(lkb, len, result); } else if (!strcmp(cmd, "getsysparam")) { const void *ptr; size_t len; if (sysparam_get_ptr(arg, &ptr, &len) == 0) { lkb_write(lkb, ptr, len); } } else if (!strcmp(cmd, "reboot")) { thread_resume(thread_create("reboot", &do_reboot, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); } else { *result = "unknown command"; return -1; } return 0; }
static int do_boot(lkb_t *lkb, size_t len, const char **result) { LTRACEF("lkb %p, len %zu, result %p\n", lkb, len, result); void *buf; paddr_t buf_phys; if (vmm_alloc_contiguous(vmm_get_kernel_aspace(), "lkboot_iobuf", len, &buf, log2_uint(1024*1024), 0, ARCH_MMU_FLAG_UNCACHED) < 0) { *result = "not enough memory"; return -1; } buf_phys = vaddr_to_paddr(buf); LTRACEF("iobuffer %p (phys 0x%lx)\n", buf, buf_phys); if (lkb_read(lkb, buf, len)) { *result = "io error"; // XXX free buffer here return -1; } /* construct a boot argument list */ const size_t bootargs_size = PAGE_SIZE; #if 0 void *args = (void *)((uintptr_t)lkb_iobuffer + lkb_iobuffer_size - bootargs_size); paddr_t args_phys = lkb_iobuffer_phys + lkb_iobuffer_size - bootargs_size; #elif PLATFORM_ZYNQ /* grab the top page of sram */ /* XXX do this better */ paddr_t args_phys = SRAM_BASE + SRAM_SIZE - bootargs_size; void *args = paddr_to_kvaddr(args_phys); #else #error need better way #endif LTRACEF("boot args %p, phys 0x%lx, len %zu\n", args, args_phys, bootargs_size); bootargs_start(args, bootargs_size); bootargs_add_command_line(args, bootargs_size, "what what"); arch_clean_cache_range((vaddr_t)args, bootargs_size); ulong lk_args[4]; bootargs_generate_lk_arg_values(args_phys, lk_args); const void *ptr; /* sniff it to see if it's a bootimage or a raw image */ bootimage_t *bi; if (bootimage_open(buf, len, &bi) >= 0) { size_t len; /* it's a bootimage */ TRACEF("detected bootimage\n"); /* find the lk image */ if (bootimage_get_file_section(bi, TYPE_LK, &ptr, &len) >= 0) { TRACEF("found lk section at %p\n", ptr); /* add the boot image to the argument list */ size_t bootimage_size; bootimage_get_range(bi, NULL, &bootimage_size); bootargs_add_bootimage_pointer(args, bootargs_size, "pmem", buf_phys, bootimage_size); } } else { /* raw image, just chain load it directly */ TRACEF("raw image, chainloading\n"); ptr = buf; } /* start a boot thread to complete the startup */ static struct chainload_args cl_args; cl_args.func = (void *)ptr; cl_args.args[0] = lk_args[0]; cl_args.args[1] = lk_args[1]; cl_args.args[2] = lk_args[2]; cl_args.args[3] = lk_args[3]; thread_resume(thread_create("boot", &chainload_thread, &cl_args, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); return 0; }