1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 3 #ifndef _IMD_H_ 4 #define _IMD_H_ 5 6 #include <stdint.h> 7 #include <stddef.h> 8 9 /* 10 * imd is an in-memory database/directory/datastore (whatever d word you 11 * desire). It grows downwards in memory from provided upper limit and 12 * root size. Each entry has a size alignment which is also provided by 13 * the caller. 14 * 15 * +----------------------+ <- upper_limit 16 * | +----| root pointer | 17 * | | +----------------------+ 18 * | | | |--------+ 19 * | +--->| root block |-----+ | 20 * | +----------------------+-----|--|--- root_size 21 * | | | | | 22 * | | | | | 23 * | | alloc N |<----+ | 24 * | +----------------------+ | 25 * | | | | 26 * | | | | 27 * \|/ | alloc N + 1 |<-------+ 28 * v +----------------------+ 29 * 30 * The root_size in imd_create_empty() encompasses the root pointer 31 * and root block. The root_size value, therefore, dictates the number 32 * of allocations maintained by the imd. 33 */ 34 35 /* 36 * NOTE: This API has the following calling conventions: all functions 37 * returning int supply 0 on success or < 0 on error. 38 */ 39 40 struct imd_entry; 41 struct imd; 42 43 static const size_t LIMIT_ALIGN = 4096; 44 45 /* 46 * Initialize handle to use for working with an imd. Upper limit is the 47 * exclusive address (aligned down to LIMIT_ALIGN) to start allocating down 48 * from. This function needs to be called at least once before any other imd 49 * related functions can be used. 50 */ 51 void imd_handle_init(struct imd *imd, void *upper_limit); 52 53 /* 54 * Initialize a handle with a shallow recovery. This function doesn't 55 * verify every entry, but it does set up the root pointer. Because of 56 * this behavior it's not very safe. However, the current CBMEM constraints 57 * demand having these semantics. 58 */ 59 void imd_handle_init_partial_recovery(struct imd *imd); 60 61 /* 62 * Create an empty imd with a specified root_size and each entry is aligned to 63 * the provided entry_align. As noted above the root size encompasses the 64 * root pointer and root block leading to the number of imd entries being a 65 * function of the root_size parameter. Please note, that one entry is allocated 66 * for covering root region, thus caller should consider this calculating 67 * root_size. 68 */ 69 int imd_create_empty(struct imd *imd, size_t root_size, size_t entry_align); 70 71 /* 72 * Create an empty imd with both large and small allocations. The small 73 * allocations come from a fixed imd stored internally within the large 74 * imd. The region allocated for tracking the smaller allocations is dependent 75 * on the small root_size and the large entry alignment by calculating the 76 * number of entries within the small imd and multiplying that by the small 77 * entry alignment. 78 */ 79 int imd_create_tiered_empty(struct imd *imd, 80 size_t lg_root_size, size_t lg_entry_align, 81 size_t sm_root_size, size_t sm_entry_align); 82 83 /* 84 * Recover a previously created imd. 85 */ 86 int imd_recover(struct imd *imd); 87 88 /* Limit imd to provided max_size. */ 89 int imd_limit_size(struct imd *imd, size_t max_size); 90 91 /* Lock down imd from further modifications. */ 92 int imd_lockdown(struct imd *imd); 93 94 /* Fill in base address and size of region used by imd. */ 95 int imd_region_used(struct imd *imd, void **base, size_t *size); 96 97 /* Add an entry to the imd. If id already exists NULL is returned. */ 98 const struct imd_entry *imd_entry_add(const struct imd *imd, uint32_t id, 99 size_t size); 100 101 /* Locate an entry within the imd. NULL is returned when not found. */ 102 const struct imd_entry *imd_entry_find(const struct imd *imd, uint32_t id); 103 104 /* Find an existing entry or add a new one. */ 105 const struct imd_entry *imd_entry_find_or_add(const struct imd *imd, 106 uint32_t id, size_t size); 107 108 /* Returns size of entry. */ 109 size_t imd_entry_size(const struct imd_entry *entry); 110 111 /* Returns pointer to region described by entry or NULL on failure. */ 112 void *imd_entry_at(const struct imd *imd, const struct imd_entry *entry); 113 114 /* Returns id for the imd entry. */ 115 uint32_t imd_entry_id(const struct imd_entry *entry); 116 117 /* Attempt to remove entry from imd. */ 118 int imd_entry_remove(const struct imd *imd, const struct imd_entry *entry); 119 120 /* Print the entry information provided by lookup with the specified size. */ 121 struct imd_lookup { 122 uint32_t id; 123 const char *name; 124 }; 125 126 int imd_print_entries(const struct imd *imd, const struct imd_lookup *lookup, 127 size_t size); 128 129 struct imd_cursor; 130 /* Initialize an imd_cursor object to walk the IMD entries. */ 131 int imd_cursor_init(const struct imd *imd, struct imd_cursor *cursor); 132 133 /* Retrieve the next imd entry the cursor is referencing. Returns NULL when 134 * no more entries exist. */ 135 const struct imd_entry *imd_cursor_next(struct imd_cursor *cursor); 136 137 /* 138 * The struct imd is a handle for working with an in-memory directory. 139 * 140 * NOTE: Do not directly touch any fields within this structure. An imd pointer 141 * is meant to be opaque, but the fields are exposed for stack allocation. 142 */ 143 struct imdr { 144 uintptr_t limit; 145 void *r; 146 }; 147 struct imd { 148 struct imdr lg; 149 struct imdr sm; 150 }; 151 152 struct imd_cursor { 153 size_t current_imdr; 154 size_t current_entry; 155 const struct imdr *imdr[2]; 156 }; 157 158 #endif /* _IMD_H_ */ 159