[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