/* SPDX-License-Identifier: GPL-2.0-only */ #ifndef _IMD_H_ #define _IMD_H_ #include #include /* * imd is an in-memory database/directory/datastore (whatever d word you * desire). It grows downwards in memory from provided upper limit and * root size. Each entry has a size alignment which is also provided by * the caller. * * +----------------------+ <- upper_limit * | +----| root pointer | * | | +----------------------+ * | | | |--------+ * | +--->| root block |-----+ | * | +----------------------+-----|--|--- root_size * | | | | | * | | | | | * | | alloc N |<----+ | * | +----------------------+ | * | | | | * | | | | * \|/ | alloc N + 1 |<-------+ * v +----------------------+ * * The root_size in imd_create_empty() encompasses the root pointer * and root block. The root_size value, therefore, dictates the number * of allocations maintained by the imd. */ /* * NOTE: This API has the following calling conventions: all functions * returning int supply 0 on success or < 0 on error. */ struct imd_entry; struct imd; static const size_t LIMIT_ALIGN = 4096; /* * Initialize handle to use for working with an imd. Upper limit is the * exclusive address (aligned down to LIMIT_ALIGN) to start allocating down * from. This function needs to be called at least once before any other imd * related functions can be used. */ void imd_handle_init(struct imd *imd, void *upper_limit); /* * Initialize a handle with a shallow recovery. This function doesn't * verify every entry, but it does set up the root pointer. Because of * this behavior it's not very safe. However, the current CBMEM constraints * demand having these semantics. */ void imd_handle_init_partial_recovery(struct imd *imd); /* * Create an empty imd with a specified root_size and each entry is aligned to * the provided entry_align. As noted above the root size encompasses the * root pointer and root block leading to the number of imd entries being a * function of the root_size parameter. Please note, that one entry is allocated * for covering root region, thus caller should consider this calculating * root_size. */ int imd_create_empty(struct imd *imd, size_t root_size, size_t entry_align); /* * Create an empty imd with both large and small allocations. The small * allocations come from a fixed imd stored internally within the large * imd. The region allocated for tracking the smaller allocations is dependent * on the small root_size and the large entry alignment by calculating the * number of entries within the small imd and multiplying that by the small * entry alignment. */ int imd_create_tiered_empty(struct imd *imd, size_t lg_root_size, size_t lg_entry_align, size_t sm_root_size, size_t sm_entry_align); /* * Recover a previously created imd. */ int imd_recover(struct imd *imd); /* Limit imd to provided max_size. */ int imd_limit_size(struct imd *imd, size_t max_size); /* Lock down imd from further modifications. */ int imd_lockdown(struct imd *imd); /* Fill in base address and size of region used by imd. */ int imd_region_used(struct imd *imd, void **base, size_t *size); /* Add an entry to the imd. If id already exists NULL is returned. */ const struct imd_entry *imd_entry_add(const struct imd *imd, uint32_t id, size_t size); /* Locate an entry within the imd. NULL is returned when not found. */ const struct imd_entry *imd_entry_find(const struct imd *imd, uint32_t id); /* Find an existing entry or add a new one. */ const struct imd_entry *imd_entry_find_or_add(const struct imd *imd, uint32_t id, size_t size); /* Returns size of entry. */ size_t imd_entry_size(const struct imd_entry *entry); /* Returns pointer to region described by entry or NULL on failure. */ void *imd_entry_at(const struct imd *imd, const struct imd_entry *entry); /* Returns id for the imd entry. */ uint32_t imd_entry_id(const struct imd_entry *entry); /* Attempt to remove entry from imd. */ int imd_entry_remove(const struct imd *imd, const struct imd_entry *entry); /* Print the entry information provided by lookup with the specified size. */ struct imd_lookup { uint32_t id; const char *name; }; int imd_print_entries(const struct imd *imd, const struct imd_lookup *lookup, size_t size); struct imd_cursor; /* Initialize an imd_cursor object to walk the IMD entries. */ int imd_cursor_init(const struct imd *imd, struct imd_cursor *cursor); /* Retrieve the next imd entry the cursor is referencing. Returns NULL when * no more entries exist. */ const struct imd_entry *imd_cursor_next(struct imd_cursor *cursor); /* * The struct imd is a handle for working with an in-memory directory. * * NOTE: Do not directly touch any fields within this structure. An imd pointer * is meant to be opaque, but the fields are exposed for stack allocation. */ struct imdr { uintptr_t limit; void *r; }; struct imd { struct imdr lg; struct imdr sm; }; struct imd_cursor { size_t current_imdr; size_t current_entry; const struct imdr *imdr[2]; }; #endif /* _IMD_H_ */