1/** 2 * \file 3 * \brief VT-d domain management 4 */ 5 6/* 7 * Copyright (c) 2014, University of Washington. 8 * All rights reserved. 9 * 10 * This file is distributed under the terms in the attached LICENSE file. 11 * If you do not find this file, copies can be found by writing to: 12 * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich. 13 * Attn: Systems Group. 14 */ 15 16#ifndef VTD_DOMAINS_H 17#define VTD_DOMAINS_H 18 19struct vtd_unit; 20 21struct vtd_domain { 22 // x86-64 VNode capability for the domain pagetable structure 23 struct capref pml4; 24 // physical address associated with capability 25 genpaddr_t pt_gp; 26 uint16_t did; 27 struct vtd_domain * prev; 28 struct vtd_domain * next; 29 // Pointer to the list of remapping hardware units 30 struct vtd_unit * units; 31}; 32 33// A domain list is a sorted and bounded doubly-linked list with 34// min_did and max_did specifying the bounds 35struct vtd_domain_list { 36 struct vtd_domain *head; 37 struct vtd_domain *tail; 38 int min_did; 39 int max_did; 40}; 41 42// Returns true if the domain list is empty, else false. 43static inline int domain_list_empty(struct vtd_domain_list *lst) 44{ 45 return (lst->head == NULL); 46} 47 48static inline struct vtd_domain_list *vtd_new_domain_list(void) 49{ 50 struct vtd_domain_list *new_list; 51 new_list = (struct vtd_domain_list *)malloc(sizeof(struct vtd_domain_list)); 52 assert(new_list != NULL); 53 new_list->head = NULL; 54 new_list->tail = NULL; 55 new_list->min_did = 0; 56 new_list->max_did = 0; 57 return new_list; 58} 59 60static inline struct vtd_domain *vtd_new_domain(int did, genpaddr_t pt, struct capref pml4, struct vtd_unit *units) 61{ 62 struct vtd_domain *new_domain = (struct vtd_domain *)malloc(sizeof(struct vtd_domain)); 63 assert(new_domain != NULL); 64 new_domain->did = did; 65 new_domain->pt_gp = pt; 66 new_domain->pml4 = pml4; 67 new_domain->next = NULL; 68 new_domain->prev = NULL; 69 new_domain->units = units; 70 return new_domain; 71} 72 73// Inserts newd as the new head of lst, a domain list with a size > 1 74static inline void vtd_insert_new_head(struct vtd_domain *newd, struct vtd_domain_list *lst) 75{ 76 newd->next = lst->head; 77 lst->head->prev = newd; 78 lst->head = newd; 79} 80 81// Inserts newd as the new tail of lst, a domain list with a size > 1 82static inline void vtd_insert_new_tail(struct vtd_domain_list *lst, struct vtd_domain *newd) 83{ 84 lst->tail->next = newd; 85 newd->prev = lst->tail; 86 lst->tail = newd; 87} 88 89// Inserts the domain newd between prevd and nextd. 90static inline void vtd_insert_between(struct vtd_domain *prevd, struct vtd_domain *newd, struct vtd_domain *nextd) 91{ 92 newd->next = nextd; 93 newd->prev = prevd; 94 prevd->next = newd; 95 nextd->prev = newd; 96} 97 98// Inserts the domain newd before the domain nextd in the domain list doms. 99static inline void vtd_insert_domain(struct vtd_domain *newd, struct vtd_domain *nextd, struct vtd_domain_list *doms) { 100 assert(newd != NULL); 101 if (domain_list_empty(doms)) { // empty 102 doms->head = newd; 103 doms->tail = newd; 104 } else if (newd->did == doms->min_did) { // new head 105 vtd_insert_new_head(newd, doms); 106 } else if (nextd == NULL) { // new tail 107 vtd_insert_new_tail(doms, newd); 108 } else { // between 109 vtd_insert_between(nextd->prev, newd, nextd); 110 } 111} 112 113// Deletes the head of lst, a domain list with a size > 1. 114static inline void vtd_delete_head(struct vtd_domain_list *lst) 115{ 116 struct vtd_domain *old_head = lst->head; 117 lst->head->next->prev = NULL; 118 lst->head = lst->head->next; 119 free(old_head); 120} 121 122// Deletes the tail of lst, a domain list with a size > 1. 123static inline void vtd_delete_tail(struct vtd_domain_list *lst) 124{ 125 struct vtd_domain *old_tail = lst->tail; 126 lst->tail->prev->next = NULL; 127 lst->tail = lst->tail->prev; 128 free(old_tail); 129} 130 131// Deletes the domain d between the domains prevd and nextd. 132static inline void vtd_delete_between(struct vtd_domain *prevd, struct vtd_domain *d, struct vtd_domain *nextd) 133{ 134 struct vtd_domain *temp = d; 135 prevd->next = nextd; 136 nextd->prev = prevd; 137 free(temp); 138} 139 140// Deletes a list of domains consisting of just a single element. 141static inline void vtd_delete_single(struct vtd_domain_list *lst) { 142 free(lst->head); 143 lst->head = NULL; 144 lst->tail = NULL; 145} 146 147// Deletes the domain d from the non-empty list of domains lst. 148static inline void vtd_delete_domain(struct vtd_domain *d, struct vtd_domain_list *lst) 149{ 150 assert(d != NULL); 151 assert(lst != NULL); 152 if (lst->head == lst->tail) { 153 vtd_delete_single(lst); 154 } else if (d == lst->head) { 155 vtd_delete_head(lst); 156 } else if (d == lst->tail) { 157 vtd_delete_tail(lst); 158 } else { 159 vtd_delete_between(d->prev, d, d->next); 160 } 161} 162 163#endif //VTD_DOMAINS_H 164