static int __init process_acpi_sdt_table(char *tab_sign, u32 *tab_data) { struct vmm_devtree_node *node = vmm_devtree_getnode(VMM_DEVTREE_PATH_SEPARATOR_STRING VMM_DEVTREE_MOTHERBOARD_NODE_NAME); /* FIXME: First find if tab_size already exists. */ struct vmm_devtree_node *cnode = vmm_devtree_addnode(node, tab_sign); vmm_devtree_dref_node(node); if (!strncmp(tab_sign, APIC_SIGNATURE, strlen(APIC_SIGNATURE))) { struct acpi_madt_hdr *madt_hdr; madt_hdr = (struct acpi_madt_hdr *)tab_data; if (acpi_populate_ioapic_devtree(madt_hdr, cnode) != VMM_OK) return VMM_EFAIL; if (acpi_populate_lapic_devtree(madt_hdr, cnode) != VMM_OK) return VMM_EFAIL; } else if (!strncmp(tab_sign, HPET_SIGNATURE, strlen(HPET_SIGNATURE))) { struct acpi_hpet hpet_chip, *hpet; int nr_hpet_blks, i; char hpet_nm[256]; if (acpi_read_sdt_at(tab_data, (struct acpi_sdt_hdr *)&hpet_chip, sizeof(struct acpi_hpet), HPET_SIGNATURE) < 0) { return VMM_EFAIL; } hpet = (struct acpi_hpet *)tab_data; nr_hpet_blks = (hpet->hdr.len - sizeof(struct acpi_sdt_hdr)) /sizeof(struct acpi_timer_blocks); vmm_devtree_setattr(cnode, VMM_DEVTREE_NR_HPET_ATTR_NAME, &nr_hpet_blks, VMM_DEVTREE_ATTRTYPE_UINT32, sizeof(nr_hpet_blks), FALSE); for (i = 0; i < nr_hpet_blks; i++) { memset(hpet_nm, 0, sizeof(hpet_nm)); vmm_sprintf(hpet_nm, VMM_DEVTREE_HPET_NODE_FMT, i); struct vmm_devtree_node *nnode = vmm_devtree_addnode(cnode, hpet_nm); BUG_ON(nnode == NULL); if (vmm_devtree_setattr(nnode, VMM_DEVTREE_HPET_ID_ATTR_NAME, &hpet->tmr_blks[i].asid, VMM_DEVTREE_ATTRTYPE_UINT32, sizeof(hpet->tmr_blks[i].asid), FALSE) != VMM_OK) { return VMM_EFAIL; } if (vmm_devtree_setattr(nnode, VMM_DEVTREE_HPET_PADDR_ATTR_NAME, &hpet->tmr_blks[i].base, VMM_DEVTREE_ATTRTYPE_PHYSADDR, sizeof(physical_addr_t), FALSE) != VMM_OK) { return VMM_EFAIL; } } } return VMM_OK; }
static int __init acpi_populate_lapic_devtree(struct acpi_madt_hdr *madt_hdr, struct vmm_devtree_node *cnode) { unsigned int idx = 0; int ret = VMM_OK; struct acpi_madt_lapic *lapic; char lapic_nm[256]; for (;;) { lapic = (struct acpi_madt_lapic *) acpi_madt_get_typed_item(madt_hdr, ACPI_MADT_TYPE_LAPIC, idx); if (!lapic) break; memset(lapic_nm, 0, sizeof(lapic_nm)); vmm_sprintf(lapic_nm, VMM_DEVTREE_LAPIC_PCPU_NODE_FMT, idx); struct vmm_devtree_node *nnode = vmm_devtree_addnode(cnode, lapic_nm); if (vmm_devtree_setattr(nnode, VMM_DEVTREE_LAPIC_CPU_ID_ATTR_NAME, &lapic->acpi_cpu_id, VMM_DEVTREE_ATTRTYPE_UINT32, sizeof(lapic->acpi_cpu_id), FALSE) != VMM_OK) { ret = VMM_EFAIL; break; } if (vmm_devtree_setattr(nnode, VMM_DEVTREE_LAPIC_LAPIC_ID_ATTR_NAME, &lapic->apic_id, VMM_DEVTREE_ATTRTYPE_UINT32, sizeof(lapic->apic_id), FALSE) != VMM_OK) { ret = VMM_EFAIL; break; } idx++; } vmm_devtree_setattr(cnode, VMM_DEVTREE_NR_LAPIC_ATTR_NAME, &idx, VMM_DEVTREE_ATTRTYPE_UINT32, sizeof(idx), FALSE); return ret; }
static int __init acpi_populate_ioapic_devtree(struct acpi_madt_hdr *madt_hdr, struct vmm_devtree_node *cnode) { unsigned int idx = 0; int ret = VMM_OK; struct acpi_madt_ioapic *ioapic; char ioapic_nm[256]; for (;;) { ioapic = (struct acpi_madt_ioapic *) acpi_madt_get_typed_item(madt_hdr, ACPI_MADT_TYPE_IOAPIC, idx); if (!ioapic) break; memset(ioapic_nm, 0, sizeof(ioapic_nm)); vmm_sprintf(ioapic_nm, VMM_DEVTREE_IOAPIC_NODE_FMT, idx); struct vmm_devtree_node *nnode = vmm_devtree_addnode(cnode, ioapic_nm); if (vmm_devtree_setattr(nnode, VMM_DEVTREE_IOAPIC_PADDR_ATTR_NAME, &ioapic->address, VMM_DEVTREE_ATTRTYPE_PHYSADDR, sizeof(physical_addr_t), FALSE) != VMM_OK) { ret = VMM_EFAIL; break; } if (vmm_devtree_setattr(nnode, VMM_DEVTREE_IOAPIC_GINT_BASE_ATTR_NAME, &ioapic->global_int_base, VMM_DEVTREE_ATTRTYPE_UINT32, sizeof(ioapic->global_int_base), FALSE) != VMM_OK) { ret = VMM_EFAIL; break; } idx++; } vmm_devtree_setattr(cnode, VMM_DEVTREE_NR_IOAPIC_ATTR_NAME, &idx, VMM_DEVTREE_ATTRTYPE_UINT32, sizeof(idx), FALSE); return ret; }
int initrd_devtree_update(u64 start, u64 end) { int rc = VMM_OK; struct vmm_devtree_node *node; /* Sanity checks */ if (start >= end) { return VMM_EINVALID; } if (initrd_rbd) { return VMM_EBUSY; } /* There should be a /chosen node */ node = vmm_devtree_getnode(VMM_DEVTREE_PATH_SEPARATOR_STRING VMM_DEVTREE_CHOSEN_NODE_NAME); if (!node) { return VMM_ENODEV; } /* Update start attribute in /chosen node */ rc = vmm_devtree_setattr(node, INITRD_START_ATTR2_NAME, &start, VMM_DEVTREE_ATTRTYPE_UINT64, sizeof(start), FALSE); if (rc) { goto done; } /* Update end attribute in /chosen node */ rc = vmm_devtree_setattr(node, INITRD_END_ATTR2_NAME, &end, VMM_DEVTREE_ATTRTYPE_UINT64, sizeof(end), FALSE); if (rc) { goto done; } done: vmm_devtree_dref_node(node); return rc; }
static void libfdt_parse_devtree_recursive(struct fdt_fileinfo * fdt, struct vmm_devtree_node * node, char **data) { u32 type, len; const char * name; struct vmm_devtree_node *child; if (!fdt || !node) { return; } while (LIBFDT_DATA32(*data) != FDT_END_NODE) { switch (LIBFDT_DATA32(*data)) { case FDT_PROP: *data += sizeof(fdt_cell_t); len = LIBFDT_DATA32(*data); *data += sizeof(fdt_cell_t); name = &fdt->str[LIBFDT_DATA32(*data)]; *data += sizeof(fdt_cell_t); type = vmm_devtree_estimate_attrtype(name); vmm_devtree_setattr(node, name, *data, type, len); *data += len; while ((virtual_addr_t) (*data) % sizeof(fdt_cell_t) != 0) (*data)++; break; case FDT_NOP: *data += sizeof(fdt_cell_t); break; case FDT_BEGIN_NODE: *data += sizeof(fdt_cell_t); type = VMM_DEVTREE_NODETYPE_UNKNOWN; child = vmm_devtree_addnode(node, *data, type, NULL); *data += vmm_strlen(*data) + 1; while ((virtual_addr_t) (*data) % sizeof(fdt_cell_t) != 0) { (*data)++; } libfdt_parse_devtree_recursive(fdt, child, data); break; default: return; break; }; } *data += sizeof(fdt_cell_t); return; }
static int cmd_vfs_fdt_load(struct vmm_chardev *cdev, const char *devtree_path, const char *devtree_root_name, const char *path, int aliasc, char **aliasv) { int a, fd, rc = VMM_OK; char *astr; const char *aname, *apath, *aattr, *atype; size_t fdt_rd; void *fdt_data, *val = NULL; u32 val_type, val_len = 0; struct stat st; struct vmm_devtree_node *root, *anode, *node; struct vmm_devtree_node *parent; struct fdt_fileinfo fdt; parent = vmm_devtree_getnode(devtree_path); if (!parent) { vmm_cprintf(cdev, "Devtree path %s does not exist.\n", devtree_path); return VMM_EINVALID; } root = vmm_devtree_getchild(parent, devtree_root_name); if (root) { vmm_devtree_dref_node(root); vmm_cprintf(cdev, "Devtree path %s/%s already exist.\n", devtree_path, devtree_root_name); rc = VMM_EINVALID; goto fail; } fd = vfs_open(path, O_RDONLY, 0); if (fd < 0) { vmm_cprintf(cdev, "Failed to open %s\n", path); rc = fd; goto fail; } rc = vfs_fstat(fd, &st); if (rc) { vmm_cprintf(cdev, "Path %s does not exist.\n", path); goto fail_closefd; } if (!(st.st_mode & S_IFREG)) { vmm_cprintf(cdev, "Path %s should be regular file.\n", path); rc = VMM_EINVALID; goto fail_closefd; } if (!st.st_size) { vmm_cprintf(cdev, "File %s has zero %d bytes.\n", path); rc = VMM_EINVALID; goto fail_closefd; } if (st.st_size > VFS_MAX_FDT_SZ) { vmm_cprintf(cdev, "File %s has size %d bytes (> %d bytes).\n", path, (long)st.st_size, VFS_MAX_FDT_SZ); rc = VMM_EINVALID; goto fail_closefd; } fdt_data = vmm_zalloc(VFS_MAX_FDT_SZ); if (!fdt_data) { rc = VMM_ENOMEM; goto fail_closefd; } fdt_rd = vfs_read(fd, fdt_data, VFS_MAX_FDT_SZ); if (fdt_rd < st.st_size) { rc = VMM_EIO; goto fail_freedata; } rc = libfdt_parse_fileinfo((virtual_addr_t)fdt_data, &fdt); if (rc) { goto fail_freedata; } root = NULL; rc = libfdt_parse_devtree(&fdt, &root, devtree_root_name, parent); if (rc) { goto fail_freedata; } anode = vmm_devtree_getchild(root, VMM_DEVTREE_ALIASES_NODE_NAME); for (a = 0; a < aliasc; a++) { if (!anode) { vmm_cprintf(cdev, "Error: %s node not available\n", VMM_DEVTREE_ALIASES_NODE_NAME); continue; } astr = aliasv[a]; aname = astr; while (*astr != '\0' && *astr != ',') { astr++; } if (*astr == ',') { *astr = '\0'; astr++; } if (*astr == '\0') { continue; } aattr = astr; while (*astr != '\0' && *astr != ',') { astr++; } if (*astr == ',') { *astr = '\0'; astr++; } if (*astr == '\0') { continue; } atype = astr; while (*astr != '\0' && *astr != ',') { astr++; } if (*astr == ',') { *astr = '\0'; astr++; } if (*astr == '\0') { continue; } if (vmm_devtree_read_string(anode, aname, &apath)) { vmm_cprintf(cdev, "Error: Failed to read %s attribute " "of %s node\n", aname, VMM_DEVTREE_ALIASES_NODE_NAME); continue; } node = vmm_devtree_getchild(root, apath); if (!node) { vmm_cprintf(cdev, "Error: %s node not found under " "%s/%s\n", apath, devtree_path, devtree_root_name); continue; } if (!strcmp(atype, "unknown")) { val = NULL; val_len = 0; val_type = VMM_DEVTREE_MAX_ATTRTYPE; } else if (!strcmp(atype, "string")) { val_len = strlen(astr) + 1; val = vmm_zalloc(val_len); if (!val) { vmm_cprintf(cdev, "Error: vmm_zalloc(%d) " "failed\n", val_len); goto next_iter; } strcpy(val, astr); val_type = VMM_DEVTREE_ATTRTYPE_STRING; } else if (!strcmp(atype, "bytes")) { val_len = 1; val = vmm_zalloc(val_len); if (!val) { vmm_cprintf(cdev, "Error: vmm_zalloc(%d) " "failed\n", val_len); goto next_iter; } *((u8 *)val) = strtoul(astr, NULL, 0); val_type = VMM_DEVTREE_ATTRTYPE_BYTEARRAY; } else if (!strcmp(atype, "uint32")) { val_len = 4; val = vmm_zalloc(val_len); if (!val) { vmm_cprintf(cdev, "Error: vmm_zalloc(%d) " "failed\n", val_len); goto next_iter; } *((u32 *)val) = strtoul(astr, NULL, 0); val_type = VMM_DEVTREE_ATTRTYPE_UINT32; } else if (!strcmp(atype, "uint64")) { val_len = 8; val = vmm_zalloc(val_len); if (!val) { vmm_cprintf(cdev, "Error: vmm_zalloc(%d) " "failed\n", val_len); goto next_iter; } *((u64 *)val) = strtoull(astr, NULL, 0); val_type = VMM_DEVTREE_ATTRTYPE_UINT64; } else if (!strcmp(atype, "physaddr")) { val_len = sizeof(physical_addr_t); val = vmm_zalloc(val_len); if (!val) { vmm_cprintf(cdev, "Error: vmm_zalloc(%d) " "failed\n", val_len); goto next_iter; } *((physical_addr_t *)val) = strtoull(astr, NULL, 0); val_type = VMM_DEVTREE_ATTRTYPE_PHYSADDR; } else if (!strcmp(atype, "physsize")) { val_len = sizeof(physical_size_t); val = vmm_zalloc(val_len); if (!val) { vmm_cprintf(cdev, "Error: vmm_zalloc(%d) " "failed\n", val_len); goto next_iter; } *((physical_size_t *)val) = strtoull(astr, NULL, 0); val_type = VMM_DEVTREE_ATTRTYPE_PHYSSIZE; } else if (!strcmp(atype, "virtaddr")) { val_len = sizeof(virtual_addr_t); val = vmm_zalloc(val_len); if (!val) { vmm_cprintf(cdev, "Error: vmm_zalloc(%d) " "failed\n", val_len); goto next_iter; } *((virtual_addr_t *)val) = strtoull(astr, NULL, 0); val_type = VMM_DEVTREE_ATTRTYPE_VIRTADDR; } else if (!strcmp(atype, "virtsize")) { val_len = sizeof(virtual_size_t); val = vmm_zalloc(val_len); if (!val) { vmm_cprintf(cdev, "Error: vmm_zalloc(%d) " "failed\n", val_len); goto next_iter; } *((virtual_size_t *)val) = strtoull(astr, NULL, 0); val_type = VMM_DEVTREE_ATTRTYPE_VIRTSIZE; } else { vmm_cprintf(cdev, "Error: Invalid attribute type %s\n", atype); goto next_iter; } if (val && (val_len > 0)) { vmm_devtree_setattr(node, aattr, val, val_type, val_len, FALSE); vmm_free(val); } next_iter: vmm_devtree_dref_node(node); } vmm_devtree_dref_node(anode); fail_freedata: vmm_free(fdt_data); fail_closefd: vfs_close(fd); fail: vmm_devtree_dref_node(parent); return rc; }
static void libfdt_parse_devtree_recursive(struct fdt_fileinfo *fdt, struct vmm_devtree_node *node, char **data) { void *val; const char *name; u32 type, len, alen, addr_cells, size_cells; struct vmm_devtree_node *child; if (!fdt || !node) { return; } if (vmm_devtree_read_u32(node->parent, "#address-cells", &addr_cells)) { addr_cells = sizeof(physical_addr_t) / sizeof(fdt_cell_t); } if (vmm_devtree_read_u32(node->parent, "#size-cells", &size_cells)) { size_cells = sizeof(physical_size_t) / sizeof(fdt_cell_t); } while (LIBFDT_DATA32(*data) != FDT_END_NODE) { switch (LIBFDT_DATA32(*data)) { case FDT_PROP: *data += sizeof(fdt_cell_t); len = LIBFDT_DATA32(*data); *data += sizeof(fdt_cell_t); name = &fdt->str[LIBFDT_DATA32(*data)]; *data += sizeof(fdt_cell_t); type = vmm_devtree_estimate_attrtype(name); alen = libfdt_property_len(name, addr_cells, size_cells, len); val = vmm_zalloc(alen); libfdt_property_read(name, val, *data, addr_cells, size_cells, len); vmm_devtree_setattr(node, name, val, type, alen); vmm_free(val); *data += len; while ((virtual_addr_t) (*data) % sizeof(fdt_cell_t) != 0) (*data)++; break; case FDT_NOP: *data += sizeof(fdt_cell_t); break; case FDT_BEGIN_NODE: *data += sizeof(fdt_cell_t); child = vmm_devtree_addnode(node, *data); *data += strlen(*data) + 1; while ((virtual_addr_t) (*data) % sizeof(fdt_cell_t) != 0) { (*data)++; } libfdt_parse_devtree_recursive(fdt, child, data); break; default: return; break; }; } *data += sizeof(fdt_cell_t); return; }