[PATCH v2 2/9] nvmem: rmem: add write and protect support
Sascha Hauer
s.hauer at pengutronix.de
Tue Jun 10 01:00:54 PDT 2025
On Thu, Jun 05, 2025 at 09:47:06AM +0200, Oleksij Rempel wrote:
> +/**
> + * rmem_is_byte_protected() - Check if a specific byte is write-protected.
> + * @rmem: Pointer to the rmem private data.
> + * @offset: Offset of the byte to check.
> + *
> + * Helper function to consult the protection bitmap.
> + *
> + * Return: True if the byte at @offset is protected, false otherwise.
> + */
> +static inline bool rmem_is_byte_protected(const struct rmem *rmem,
> + unsigned int offset)
> +{
> + unsigned char bit_mask;
> + unsigned int byte_idx;
> +
> + byte_idx = offset / 8;
> + bit_mask = 1U << (offset % 8);
> + return (rmem->protection_bitmap[byte_idx] & bit_mask) != 0;
test_bit();
> +}
> +
> +/**
> + * rmem_do_protect_byte() - Mark a specific byte as write-protected.
> + * @rmem: Pointer to the rmem private data.
> + * @offset: Offset of the byte to protect.
> + *
> + * Helper function to set a bit in the protection bitmap. Assumes @offset
> + * is valid and rmem->protection_bitmap is allocated.
> + */
> +static inline void rmem_do_protect_byte(struct rmem *rmem, unsigned int offset)
> +{
> + unsigned char bit_mask = 1U << (offset % 8);
> + unsigned int byte_idx = offset / 8;
> +
> + rmem->protection_bitmap[byte_idx] |= bit_mask;
set_bit();
> +}
> +
> +/**
> + * rmem_do_unprotect_byte() - Mark a specific byte as writable.
> + * @rmem: Pointer to the rmem private data.
> + * @offset: Offset of the byte to unprotect.
> + *
> + * Helper function to clear a bit in the protection bitmap. Assumes @offset
> + * is valid and rmem->protection_bitmap is allocated.
> + */
> +static inline void rmem_do_unprotect_byte(struct rmem *rmem,
> + unsigned int offset)
> +{
> + unsigned int byte_idx = offset / 8;
> + unsigned char bit_mask = 1U << (offset % 8);
> +
> + rmem->protection_bitmap[byte_idx] &= ~bit_mask;
clear_bit();
> +}
> +
> +/**
> + * rmem_write() - Write data to the NVMEM device.
> + * @context: Pointer to the rmem private data (struct rmem).
> + * @offset: Offset within the NVMEM device to write to.
> + * @val: Buffer containing the data to write.
> + * @bytes: Number of bytes to write.
> + *
> + * This function is called by the NVMEM core to write data to the
> + * reserved memory region. It first checks the protection bitmap to ensure
> + * the target range is not write-protected. If writable, it uses the
> + * custom 'mem_copy' function.
> + * Specific error codes include -EROFS if protected or -EINVAL for bad params.
> + *
> + * Return: 0 on success, or a negative error code on failure.
> + */
> +static int rmem_write(void *context, unsigned int offset, const void *val,
> + size_t bytes)
> +{
> + struct rmem *rmem = context;
> + unsigned int i;
> +
> + for (i = 0; i < bytes; ++i) {
> + if (rmem_is_byte_protected(rmem, offset + i)) {
> + dev_warn(rmem->dev,
> + "Write [0x%x, len %zu] denied at 0x%x (protected)\n",
> + offset, bytes, offset + i);
> + return -EROFS;
> + }
> + }
> +
if (find_next_bit(rmem->prot_map, offset + bytes, offset) < offset + bytes)
return -EROFS;
> + /*
> + * The last two arguments to mem_copy (0, 0) are specific to
> + * the custom mem_copy implementation.
> + */
> + return mem_copy(rmem->dev, (void *)rmem->mem->start + offset, val,
> + bytes, 0, 0);
> +}
> +
> +/**
> + * rmem_set_protection_bits() - Mark a memory range as read-only.
> + * @rmem: Pointer to the rmem private data.
> + * @offset: Starting offset of the range to protect.
> + * @bytes: Length of the range to protect in bytes.
> + *
> + * Sets the corresponding bits in the protection_bitmap to mark the
> + * specified memory range as write-protected (read-only).
> + *
> + * Return: 0 on success, or a negative error code on failure.
> + */
> +static int rmem_set_protection_bits(struct rmem *rmem, unsigned int offset,
> + size_t bytes)
> +{
> + unsigned int end_offset = offset + bytes;
> + unsigned int i;
> +
> + for (i = offset; i < end_offset; ++i)
> + rmem_do_protect_byte(rmem, i);
bitmap_set();
> +
> + dev_info(rmem->dev, "Protected range [0x%x, len %zu]\n", offset,
> + bytes);
> + return 0;
> +}
> +
> +/**
> + * rmem_clear_protection_bits() - Mark a memory range as writable.
> + * @rmem: Pointer to the rmem private data.
> + * @offset: Starting offset of the range to unprotect.
> + * @bytes: Length of the range to unprotect in bytes.
> + *
> + * Clears the corresponding bits in the protection_bitmap to mark the
> + * specified memory range as writable.
> + *
> + * Return: 0 on success, or a negative error code on failure.
> + */
> +static int rmem_clear_protection_bits(struct rmem *rmem, unsigned int offset,
> + size_t bytes)
> +{
> + unsigned int end_offset = offset + bytes;
> + unsigned int i;
> +
> + for (i = offset; i < end_offset; ++i)
> + rmem_do_unprotect_byte(rmem, i);
bitmap_clear();
> +
> + dev_info(rmem->dev, "Unprotected range [0x%x, len %zu]\n", offset,
> + bytes);
> + return 0;
> +}
> +
> static int rmem_probe(struct device *dev)
> {
> struct nvmem_config config = { };
> @@ -41,7 +229,14 @@ static int rmem_probe(struct device *dev)
> config.priv = priv;
> config.name = "rmem";
> config.size = resource_size(mem);
> + priv->total_size = config.size;
> +
> + priv->protection_bitmap_bytes = DIV_ROUND_UP(priv->total_size, 8);
> + priv->protection_bitmap = xzalloc(priv->protection_bitmap_bytes);
bitmap_xzalloc();
Sascha
--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
More information about the barebox
mailing list