diff mbox series

[v3,3/6] lib: sbi: Add sbi_domain_check_addr_range() function

Message ID 20221124132906.257732-4-apatel@ventanamicro.com
State Superseded
Headers show
Series OpenSBI debug console support | expand

Commit Message

Anup Patel Nov. 24, 2022, 1:29 p.m. UTC
We add sbi_domain_check_addr_range() helper function to check
whether a given address range is accessible under a particular
domain.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
 include/sbi/sbi_domain.h | 15 +++++++++
 lib/sbi/sbi_domain.c     | 69 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 84 insertions(+)

Comments

Xiang W Nov. 25, 2022, 2:01 a.m. UTC | #1
在 2022-11-24星期四的 18:59 +0530,Anup Patel写道:
> We add sbi_domain_check_addr_range() helper function to check
> whether a given address range is accessible under a particular
> domain.
> 
> Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Look good to me

Reviewed-by: Xiang W <wxjstz@126.com>
> ---
>  include/sbi/sbi_domain.h | 15 +++++++++
>  lib/sbi/sbi_domain.c     | 69 ++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 84 insertions(+)
> 
> diff --git a/include/sbi/sbi_domain.h b/include/sbi/sbi_domain.h
> index 5553d21..4afcc37 100644
> --- a/include/sbi/sbi_domain.h
> +++ b/include/sbi/sbi_domain.h
> @@ -154,6 +154,21 @@ bool sbi_domain_check_addr(const struct sbi_domain *dom,
>                            unsigned long addr, unsigned long mode,
>                            unsigned long access_flags);
>  
> +/**
> + * Check whether we can access specified address range for given mode and
> + * memory region flags under a domain
> + * @param dom pointer to domain
> + * @param addr the start of the address range to be checked
> + * @param size the size of the address range to be checked
> + * @param mode the privilege mode of access
> + * @param access_flags bitmask of domain access types (enum sbi_domain_access)
> + * @return TRUE if access allowed otherwise FALSE
> + */
> +bool sbi_domain_check_addr_range(const struct sbi_domain *dom,
> +                                unsigned long addr, unsigned long size,
> +                                unsigned long mode,
> +                                unsigned long access_flags);
> +
>  /** Dump domain details on the console */
>  void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix);
>  
> diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c
> index f24a8e5..11a547c 100644
> --- a/lib/sbi/sbi_domain.c
> +++ b/lib/sbi/sbi_domain.c
> @@ -195,6 +195,44 @@ static bool is_region_before(const struct sbi_domain_memregion *regA,
>         return FALSE;
>  }
>  
> +static const struct sbi_domain_memregion *find_region(
> +                                               const struct sbi_domain *dom,
> +                                               unsigned long addr)
> +{
> +       unsigned long rstart, rend;
> +       struct sbi_domain_memregion *reg;
> +
> +       sbi_domain_for_each_memregion(dom, reg) {
> +               rstart = reg->base;
> +               rend = (reg->order < __riscv_xlen) ?
> +                       rstart + ((1UL << reg->order) - 1) : -1UL;
> +               if (rstart <= addr && addr <= rend)
> +                       return reg;
> +       }
> +
> +       return NULL;
> +}
> +
> +static const struct sbi_domain_memregion *find_next_subset_region(
> +                               const struct sbi_domain *dom,
> +                               const struct sbi_domain_memregion *reg,
> +                               unsigned long addr)
> +{
> +       struct sbi_domain_memregion *sreg, *ret = NULL;
> +
> +       sbi_domain_for_each_memregion(dom, sreg) {
> +               if (sreg == reg || (sreg->base <= addr) ||
> +                   !is_region_subset(sreg, reg))
> +                       continue;
> +
> +               if (!ret || (sreg->base < ret->base) ||
> +                   ((sreg->base == ret->base) && (sreg->order < ret->order)))
> +                       ret = sreg;
> +       }
> +
> +       return ret;
> +}
> +
>  static int sanitize_domain(const struct sbi_platform *plat,
>                            struct sbi_domain *dom)
>  {
> @@ -303,6 +341,37 @@ static int sanitize_domain(const struct sbi_platform *plat,
>         return 0;
>  }
>  
> +bool sbi_domain_check_addr_range(const struct sbi_domain *dom,
> +                                unsigned long addr, unsigned long size,
> +                                unsigned long mode,
> +                                unsigned long access_flags)
> +{
> +       unsigned long max = addr + size;
> +       const struct sbi_domain_memregion *reg, *sreg;
> +
> +       if (!dom)
> +               return FALSE;
> +
> +       while (addr < max) {
> +               reg = find_region(dom, addr);
> +               if (!reg)
> +                       return FALSE;
> +
> +               if (!sbi_domain_check_addr(dom, addr, mode, access_flags))
> +                       return FALSE;
> +
> +               sreg = find_next_subset_region(dom, reg, addr);
> +               if (sreg)
> +                       addr = sreg->base;
> +               else if (reg->order < __riscv_xlen)
> +                       addr = reg->base + (1UL << reg->order);
> +               else
> +                       break;
> +       }
> +
> +       return TRUE;
> +}
> +
>  void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
>  {
>         u32 i, k;
> -- 
> 2.34.1
> 
>
Bin Meng Dec. 21, 2022, 9:30 a.m. UTC | #2
On Thu, Nov 24, 2022 at 9:32 PM Anup Patel <apatel@ventanamicro.com> wrote:
>
> We add sbi_domain_check_addr_range() helper function to check
> whether a given address range is accessible under a particular
> domain.
>
> Signed-off-by: Anup Patel <apatel@ventanamicro.com>
> ---
>  include/sbi/sbi_domain.h | 15 +++++++++
>  lib/sbi/sbi_domain.c     | 69 ++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 84 insertions(+)
>
> diff --git a/include/sbi/sbi_domain.h b/include/sbi/sbi_domain.h
> index 5553d21..4afcc37 100644
> --- a/include/sbi/sbi_domain.h
> +++ b/include/sbi/sbi_domain.h
> @@ -154,6 +154,21 @@ bool sbi_domain_check_addr(const struct sbi_domain *dom,
>                            unsigned long addr, unsigned long mode,
>                            unsigned long access_flags);
>
> +/**
> + * Check whether we can access specified address range for given mode and
> + * memory region flags under a domain
> + * @param dom pointer to domain
> + * @param addr the start of the address range to be checked
> + * @param size the size of the address range to be checked
> + * @param mode the privilege mode of access
> + * @param access_flags bitmask of domain access types (enum sbi_domain_access)
> + * @return TRUE if access allowed otherwise FALSE
> + */
> +bool sbi_domain_check_addr_range(const struct sbi_domain *dom,
> +                                unsigned long addr, unsigned long size,
> +                                unsigned long mode,
> +                                unsigned long access_flags);
> +
>  /** Dump domain details on the console */
>  void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix);
>
> diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c
> index f24a8e5..11a547c 100644
> --- a/lib/sbi/sbi_domain.c
> +++ b/lib/sbi/sbi_domain.c
> @@ -195,6 +195,44 @@ static bool is_region_before(const struct sbi_domain_memregion *regA,
>         return FALSE;
>  }
>
> +static const struct sbi_domain_memregion *find_region(
> +                                               const struct sbi_domain *dom,
> +                                               unsigned long addr)
> +{
> +       unsigned long rstart, rend;
> +       struct sbi_domain_memregion *reg;
> +
> +       sbi_domain_for_each_memregion(dom, reg) {
> +               rstart = reg->base;
> +               rend = (reg->order < __riscv_xlen) ?
> +                       rstart + ((1UL << reg->order) - 1) : -1UL;
> +               if (rstart <= addr && addr <= rend)

addr < rend?

> +                       return reg;
> +       }
> +
> +       return NULL;
> +}
> +
> +static const struct sbi_domain_memregion *find_next_subset_region(
> +                               const struct sbi_domain *dom,
> +                               const struct sbi_domain_memregion *reg,
> +                               unsigned long addr)
> +{
> +       struct sbi_domain_memregion *sreg, *ret = NULL;
> +
> +       sbi_domain_for_each_memregion(dom, sreg) {
> +               if (sreg == reg || (sreg->base <= addr) ||
> +                   !is_region_subset(sreg, reg))
> +                       continue;
> +
> +               if (!ret || (sreg->base < ret->base) ||
> +                   ((sreg->base == ret->base) && (sreg->order < ret->order)))
> +                       ret = sreg;
> +       }
> +
> +       return ret;
> +}
> +
>  static int sanitize_domain(const struct sbi_platform *plat,
>                            struct sbi_domain *dom)
>  {
> @@ -303,6 +341,37 @@ static int sanitize_domain(const struct sbi_platform *plat,
>         return 0;
>  }
>
> +bool sbi_domain_check_addr_range(const struct sbi_domain *dom,
> +                                unsigned long addr, unsigned long size,
> +                                unsigned long mode,
> +                                unsigned long access_flags)
> +{
> +       unsigned long max = addr + size;
> +       const struct sbi_domain_memregion *reg, *sreg;
> +
> +       if (!dom)
> +               return FALSE;
> +
> +       while (addr < max) {
> +               reg = find_region(dom, addr);
> +               if (!reg)
> +                       return FALSE;
> +
> +               if (!sbi_domain_check_addr(dom, addr, mode, access_flags))
> +                       return FALSE;
> +
> +               sreg = find_next_subset_region(dom, reg, addr);
> +               if (sreg)
> +                       addr = sreg->base;
> +               else if (reg->order < __riscv_xlen)
> +                       addr = reg->base + (1UL << reg->order);
> +               else
> +                       break;
> +       }
> +
> +       return TRUE;
> +}
> +
>  void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
>  {
>         u32 i, k;

Regards,
Bin
Bin Meng Dec. 21, 2022, 10:17 a.m. UTC | #3
On Wed, Dec 21, 2022 at 5:30 PM Bin Meng <bmeng.cn@gmail.com> wrote:
>
> On Thu, Nov 24, 2022 at 9:32 PM Anup Patel <apatel@ventanamicro.com> wrote:
> >
> > We add sbi_domain_check_addr_range() helper function to check
> > whether a given address range is accessible under a particular
> > domain.
> >
> > Signed-off-by: Anup Patel <apatel@ventanamicro.com>
> > ---
> >  include/sbi/sbi_domain.h | 15 +++++++++
> >  lib/sbi/sbi_domain.c     | 69 ++++++++++++++++++++++++++++++++++++++++
> >  2 files changed, 84 insertions(+)
> >
> > diff --git a/include/sbi/sbi_domain.h b/include/sbi/sbi_domain.h
> > index 5553d21..4afcc37 100644
> > --- a/include/sbi/sbi_domain.h
> > +++ b/include/sbi/sbi_domain.h
> > @@ -154,6 +154,21 @@ bool sbi_domain_check_addr(const struct sbi_domain *dom,
> >                            unsigned long addr, unsigned long mode,
> >                            unsigned long access_flags);
> >
> > +/**
> > + * Check whether we can access specified address range for given mode and
> > + * memory region flags under a domain
> > + * @param dom pointer to domain
> > + * @param addr the start of the address range to be checked
> > + * @param size the size of the address range to be checked
> > + * @param mode the privilege mode of access
> > + * @param access_flags bitmask of domain access types (enum sbi_domain_access)
> > + * @return TRUE if access allowed otherwise FALSE
> > + */
> > +bool sbi_domain_check_addr_range(const struct sbi_domain *dom,
> > +                                unsigned long addr, unsigned long size,
> > +                                unsigned long mode,
> > +                                unsigned long access_flags);
> > +
> >  /** Dump domain details on the console */
> >  void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix);
> >
> > diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c
> > index f24a8e5..11a547c 100644
> > --- a/lib/sbi/sbi_domain.c
> > +++ b/lib/sbi/sbi_domain.c
> > @@ -195,6 +195,44 @@ static bool is_region_before(const struct sbi_domain_memregion *regA,
> >         return FALSE;
> >  }
> >
> > +static const struct sbi_domain_memregion *find_region(
> > +                                               const struct sbi_domain *dom,
> > +                                               unsigned long addr)
> > +{
> > +       unsigned long rstart, rend;
> > +       struct sbi_domain_memregion *reg;
> > +
> > +       sbi_domain_for_each_memregion(dom, reg) {
> > +               rstart = reg->base;
> > +               rend = (reg->order < __riscv_xlen) ?
> > +                       rstart + ((1UL << reg->order) - 1) : -1UL;
> > +               if (rstart <= addr && addr <= rend)
>
> addr < rend?

Never mind. Looks good.

>
> > +                       return reg;
> > +       }
> > +
> > +       return NULL;
> > +}
> > +
> > +static const struct sbi_domain_memregion *find_next_subset_region(
> > +                               const struct sbi_domain *dom,
> > +                               const struct sbi_domain_memregion *reg,
> > +                               unsigned long addr)
> > +{
> > +       struct sbi_domain_memregion *sreg, *ret = NULL;
> > +
> > +       sbi_domain_for_each_memregion(dom, sreg) {
> > +               if (sreg == reg || (sreg->base <= addr) ||
> > +                   !is_region_subset(sreg, reg))
> > +                       continue;
> > +
> > +               if (!ret || (sreg->base < ret->base) ||
> > +                   ((sreg->base == ret->base) && (sreg->order < ret->order)))
> > +                       ret = sreg;
> > +       }
> > +
> > +       return ret;
> > +}
> > +
> >  static int sanitize_domain(const struct sbi_platform *plat,
> >                            struct sbi_domain *dom)
> >  {
> > @@ -303,6 +341,37 @@ static int sanitize_domain(const struct sbi_platform *plat,
> >         return 0;
> >  }
> >
> > +bool sbi_domain_check_addr_range(const struct sbi_domain *dom,
> > +                                unsigned long addr, unsigned long size,
> > +                                unsigned long mode,
> > +                                unsigned long access_flags)
> > +{
> > +       unsigned long max = addr + size;
> > +       const struct sbi_domain_memregion *reg, *sreg;
> > +
> > +       if (!dom)
> > +               return FALSE;
> > +
> > +       while (addr < max) {
> > +               reg = find_region(dom, addr);
> > +               if (!reg)
> > +                       return FALSE;
> > +
> > +               if (!sbi_domain_check_addr(dom, addr, mode, access_flags))
> > +                       return FALSE;
> > +
> > +               sreg = find_next_subset_region(dom, reg, addr);
> > +               if (sreg)
> > +                       addr = sreg->base;
> > +               else if (reg->order < __riscv_xlen)
> > +                       addr = reg->base + (1UL << reg->order);
> > +               else
> > +                       break;
> > +       }
> > +
> > +       return TRUE;
> > +}
> > +
> >  void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
> >  {
> >         u32 i, k;
>

Reviewed-by: Bin Meng <bmeng@tinylab.org>
diff mbox series

Patch

diff --git a/include/sbi/sbi_domain.h b/include/sbi/sbi_domain.h
index 5553d21..4afcc37 100644
--- a/include/sbi/sbi_domain.h
+++ b/include/sbi/sbi_domain.h
@@ -154,6 +154,21 @@  bool sbi_domain_check_addr(const struct sbi_domain *dom,
 			   unsigned long addr, unsigned long mode,
 			   unsigned long access_flags);
 
+/**
+ * Check whether we can access specified address range for given mode and
+ * memory region flags under a domain
+ * @param dom pointer to domain
+ * @param addr the start of the address range to be checked
+ * @param size the size of the address range to be checked
+ * @param mode the privilege mode of access
+ * @param access_flags bitmask of domain access types (enum sbi_domain_access)
+ * @return TRUE if access allowed otherwise FALSE
+ */
+bool sbi_domain_check_addr_range(const struct sbi_domain *dom,
+				 unsigned long addr, unsigned long size,
+				 unsigned long mode,
+				 unsigned long access_flags);
+
 /** Dump domain details on the console */
 void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix);
 
diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c
index f24a8e5..11a547c 100644
--- a/lib/sbi/sbi_domain.c
+++ b/lib/sbi/sbi_domain.c
@@ -195,6 +195,44 @@  static bool is_region_before(const struct sbi_domain_memregion *regA,
 	return FALSE;
 }
 
+static const struct sbi_domain_memregion *find_region(
+						const struct sbi_domain *dom,
+						unsigned long addr)
+{
+	unsigned long rstart, rend;
+	struct sbi_domain_memregion *reg;
+
+	sbi_domain_for_each_memregion(dom, reg) {
+		rstart = reg->base;
+		rend = (reg->order < __riscv_xlen) ?
+			rstart + ((1UL << reg->order) - 1) : -1UL;
+		if (rstart <= addr && addr <= rend)
+			return reg;
+	}
+
+	return NULL;
+}
+
+static const struct sbi_domain_memregion *find_next_subset_region(
+				const struct sbi_domain *dom,
+				const struct sbi_domain_memregion *reg,
+				unsigned long addr)
+{
+	struct sbi_domain_memregion *sreg, *ret = NULL;
+
+	sbi_domain_for_each_memregion(dom, sreg) {
+		if (sreg == reg || (sreg->base <= addr) ||
+		    !is_region_subset(sreg, reg))
+			continue;
+
+		if (!ret || (sreg->base < ret->base) ||
+		    ((sreg->base == ret->base) && (sreg->order < ret->order)))
+			ret = sreg;
+	}
+
+	return ret;
+}
+
 static int sanitize_domain(const struct sbi_platform *plat,
 			   struct sbi_domain *dom)
 {
@@ -303,6 +341,37 @@  static int sanitize_domain(const struct sbi_platform *plat,
 	return 0;
 }
 
+bool sbi_domain_check_addr_range(const struct sbi_domain *dom,
+				 unsigned long addr, unsigned long size,
+				 unsigned long mode,
+				 unsigned long access_flags)
+{
+	unsigned long max = addr + size;
+	const struct sbi_domain_memregion *reg, *sreg;
+
+	if (!dom)
+		return FALSE;
+
+	while (addr < max) {
+		reg = find_region(dom, addr);
+		if (!reg)
+			return FALSE;
+
+		if (!sbi_domain_check_addr(dom, addr, mode, access_flags))
+			return FALSE;
+
+		sreg = find_next_subset_region(dom, reg, addr);
+		if (sreg)
+			addr = sreg->base;
+		else if (reg->order < __riscv_xlen)
+			addr = reg->base + (1UL << reg->order);
+		else
+			break;
+	}
+
+	return TRUE;
+}
+
 void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
 {
 	u32 i, k;