/* $NetBSD: mdesc.c,v 1.6 2015/09/07 17:14:54 uebayasi Exp $ */ /* $OpenBSD: mdesc.c,v 1.7 2014/11/30 22:26:15 kettenis Exp $ */ /* * Copyright (c) 2009 Mark Kettenis * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include vaddr_t mdesc; paddr_t mdesc_pa; size_t mdesc_len; psize_t mdesc_get_len(void) { psize_t len = 0; len = 0; hv_mach_desc(0, &len); KASSERT(len != 0); return len; } void mdesc_init(vaddr_t va, paddr_t pa, psize_t avail_len) { psize_t len; int64_t err; len = avail_len; err = hv_mach_desc(pa, &len); if (err != H_EOK) panic("hv_mach_desc() failed - err = %" PRId64 "\n", err); KASSERT(len <= avail_len); mdesc = (vaddr_t)va; mdesc_pa = pa; mdesc_len = len; return; } uint64_t mdesc_get_prop_val(int idx, const char *name) { struct md_header *hdr; struct md_element *elem; const char *name_blk; const char *str; hdr = (struct md_header *)mdesc; elem = (struct md_element *)(mdesc + sizeof(struct md_header)); name_blk = (char *)mdesc + sizeof(struct md_header) + hdr->node_blk_sz; while (elem[idx].tag != 'E') { str = name_blk + elem[idx].name_offset; if (elem[idx].tag == 'v' && strcmp(str, name) == 0) return (elem[idx].d.val); idx++; } return (-1); } const char * mdesc_get_prop_str(int idx, const char *name) { struct md_header *hdr; struct md_element *elem; const char *name_blk; const char *data_blk; const char *str; hdr = (struct md_header *)mdesc; elem = (struct md_element *)(mdesc + sizeof(struct md_header)); name_blk = (char *)mdesc + sizeof(struct md_header) + hdr->node_blk_sz; data_blk = name_blk + hdr->name_blk_sz; while (elem[idx].tag != 'E') { str = name_blk + elem[idx].name_offset; if (elem[idx].tag == 's' && strcmp(str, name) == 0) return (data_blk + elem[idx].d.y.data_offset); idx++; } return (NULL); } const char * mdesc_get_prop_data(int idx, const char *name, size_t *len) { struct md_header *hdr; struct md_element *elem; const char *name_blk; const char *data_blk; const char *str; hdr = (struct md_header *)mdesc; elem = (struct md_element *)(mdesc + sizeof(struct md_header)); name_blk = (char *)mdesc + sizeof(struct md_header) + hdr->node_blk_sz; data_blk = name_blk + hdr->name_blk_sz; while (elem[idx].tag != 'E') { str = name_blk + elem[idx].name_offset; if (elem[idx].tag == 'd' && strcmp(str, name) == 0) { *len = elem[idx].d.y.data_len; return (data_blk + elem[idx].d.y.data_offset); } idx++; } return (NULL); } int mdesc_find(const char *name, uint64_t cfg_handle) { struct md_header *hdr; struct md_element *elem; const char *str; uint64_t val; int idx; hdr = (struct md_header *)mdesc; (void)hdr; /* XXX avoid compiler warning */ elem = (struct md_element *)(mdesc + sizeof(struct md_header)); for (idx = 0; elem[idx].tag == 'N'; idx = elem[idx].d.val) { str = mdesc_get_prop_str(idx, "name"); val = mdesc_get_prop_val(idx, "cfg-handle"); if (str && strcmp(str, name) == 0 && val == cfg_handle) return (idx); } return (-1); } int mdesc_find_child(int idx, const char *name, uint64_t cfg_handle) { struct md_header *hdr; struct md_element *elem; const char *name_blk; const char *str; uint64_t val; int arc; hdr = (struct md_header *)mdesc; elem = (struct md_element *)(mdesc + sizeof(struct md_header)); name_blk = (char *)mdesc + sizeof(struct md_header) + hdr->node_blk_sz; for (; elem[idx].tag != 'E'; idx++) { str = name_blk + elem[idx].name_offset; if (elem[idx].tag != 'a' || strcmp(str, "fwd") != 0) continue; arc = elem[idx].d.val; str = mdesc_get_prop_str(arc, "name"); val = mdesc_get_prop_val(arc, "cfg-handle"); if (str && strcmp(str, name) == 0 && val == cfg_handle) return (arc); } return (-1); } int mdesc_find_node_by_idx(int idx, const char *name) { struct md_header *hdr; struct md_element *elem; const char *name_blk; const char *str; hdr = (struct md_header *)mdesc; elem = (struct md_element *)(mdesc + sizeof(struct md_header)); name_blk = (char *)mdesc + sizeof(struct md_header) + hdr->node_blk_sz; for ( ; elem[idx].tag == 'N'; idx = elem[idx].d.val) { str = name_blk + elem[idx].name_offset; if (str && strcmp(str, name) == 0) return (idx); } return (-1); } int mdesc_find_node(const char *name) { return mdesc_find_node_by_idx(0, name); } int mdesc_next_node(int idx) { struct md_element *elem; elem = (struct md_element *)(mdesc + sizeof(struct md_header)); return elem[idx].d.val; } const char * mdesc_name_by_idx(int idx) { struct md_header *hdr; struct md_element *elem; const char *name_blk; const char *str; hdr = (struct md_header *)mdesc; elem = (struct md_element *)(mdesc + sizeof(struct md_header)); name_blk = (char *)mdesc + sizeof(struct md_header) + hdr->node_blk_sz; str = name_blk + elem[idx].name_offset; return str; }