diff mbox series

[2/5] lib: sbi: Allow specifying mode in sbi_hart_pmp_check_addr() API

Message ID 20200909145028.446794-3-anup.patel@wdc.com
State Accepted
Headers show
Series Hold E-core in HSM STOPPED State | expand

Commit Message

Anup Patel Sept. 9, 2020, 2:50 p.m. UTC
We extend sbi_hart_pmp_check_addr() API so that users can specify
privilege mode of the address for checking PMP access permissions.

To achieve this, we end-up converting "unsigned long *size" parameter
to "unsigned long *log2len" for pmp_get() implementation so that we
can deal with regions of "1UL << __riscv_xlen" size in a special case
in sbi_hart_pmp_check_addr() implementation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
---
 include/sbi/riscv_asm.h |  2 +-
 include/sbi/sbi_hart.h  |  3 ++-
 lib/sbi/riscv_asm.c     | 18 ++++++++----------
 lib/sbi/sbi_hart.c      | 28 +++++++++++++++++++++-------
 lib/sbi/sbi_hsm.c       |  2 +-
 5 files changed, 33 insertions(+), 20 deletions(-)

Comments

Atish Patra Sept. 15, 2020, 7:32 a.m. UTC | #1
On Wed, Sep 9, 2020 at 7:51 AM Anup Patel <anup.patel@wdc.com> wrote:
>
> We extend sbi_hart_pmp_check_addr() API so that users can specify
> privilege mode of the address for checking PMP access permissions.
>
> To achieve this, we end-up converting "unsigned long *size" parameter
> to "unsigned long *log2len" for pmp_get() implementation so that we
> can deal with regions of "1UL << __riscv_xlen" size in a special case
> in sbi_hart_pmp_check_addr() implementation.
>
> Signed-off-by: Anup Patel <anup.patel@wdc.com>
> ---
>  include/sbi/riscv_asm.h |  2 +-
>  include/sbi/sbi_hart.h  |  3 ++-
>  lib/sbi/riscv_asm.c     | 18 ++++++++----------
>  lib/sbi/sbi_hart.c      | 28 +++++++++++++++++++++-------
>  lib/sbi/sbi_hsm.c       |  2 +-
>  5 files changed, 33 insertions(+), 20 deletions(-)
>
> diff --git a/include/sbi/riscv_asm.h b/include/sbi/riscv_asm.h
> index 6e093ca..10f31a7 100644
> --- a/include/sbi/riscv_asm.h
> +++ b/include/sbi/riscv_asm.h
> @@ -180,7 +180,7 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
>             unsigned long log2len);
>
>  int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
> -           unsigned long *size);
> +           unsigned long *log2len);
>
>  #endif /* !__ASSEMBLY__ */
>
> diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h
> index 1e1eb67..0ba68f0 100644
> --- a/include/sbi/sbi_hart.h
> +++ b/include/sbi/sbi_hart.h
> @@ -42,7 +42,8 @@ int sbi_hart_pmp_get(struct sbi_scratch *scratch, unsigned int n,
>                      unsigned long *prot_out, unsigned long *addr_out,
>                      unsigned long *size);
>  void sbi_hart_pmp_dump(struct sbi_scratch *scratch);
> -int  sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long daddr,
> +int  sbi_hart_pmp_check_addr(struct sbi_scratch *scratch,
> +                            unsigned long daddr, unsigned long mode,
>                              unsigned long attr);
>  bool sbi_hart_has_feature(struct sbi_scratch *scratch, unsigned long feature);
>  void sbi_hart_get_features_str(struct sbi_scratch *scratch,
> diff --git a/lib/sbi/riscv_asm.c b/lib/sbi/riscv_asm.c
> index 799123f..8c54c11 100644
> --- a/lib/sbi/riscv_asm.c
> +++ b/lib/sbi/riscv_asm.c
> @@ -239,16 +239,16 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
>  }
>
>  int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
> -           unsigned long *size)
> +           unsigned long *log2len)
>  {
>         int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr;
>         unsigned long cfgmask, pmpcfg, prot;
> -       unsigned long t1, addr, log2len;
> +       unsigned long t1, addr, len;
>
>         /* check parameters */
> -       if (n >= PMP_COUNT || !prot_out || !addr_out || !size)
> +       if (n >= PMP_COUNT || !prot_out || !addr_out || !log2len)
>                 return SBI_EINVAL;
> -       *prot_out = *addr_out = *size = 0;
> +       *prot_out = *addr_out = *log2len = 0;
>
>         /* calculate PMP register and offset */
>  #if __riscv_xlen == 32
> @@ -275,23 +275,21 @@ int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
>                 addr = csr_read_num(pmpaddr_csr);
>                 if (addr == -1UL) {
>                         addr    = 0;
> -                       log2len = __riscv_xlen;
> +                       len     = __riscv_xlen;
>                 } else {
>                         t1      = ctz(~addr);
>                         addr    = (addr & ~((1UL << t1) - 1)) << PMP_SHIFT;
> -                       log2len = (t1 + PMP_SHIFT + 1);
> +                       len     = (t1 + PMP_SHIFT + 1);
>                 }
>         } else {
>                 addr    = csr_read_num(pmpaddr_csr) << PMP_SHIFT;
> -               log2len = PMP_SHIFT;
> +               len     = PMP_SHIFT;
>         }
>
>         /* return details */
>         *prot_out    = prot;
>         *addr_out    = addr;
> -
> -       if (log2len < __riscv_xlen)
> -               *size = (1UL << log2len);
> +       *log2len     = len;
>
>         return 0;
>  }
> diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c
> index d788918..4cbe8ce 100644
> --- a/lib/sbi/sbi_hart.c
> +++ b/lib/sbi/sbi_hart.c
> @@ -156,22 +156,31 @@ int sbi_hart_pmp_get(struct sbi_scratch *scratch, unsigned int n,
>                      unsigned long *prot_out, unsigned long *addr_out,
>                      unsigned long *size)
>  {
> +       int err;
> +       unsigned long log2size;
> +
>         if (sbi_hart_pmp_count(scratch) <= n)
>                 return SBI_EINVAL;
>
> -       return pmp_get(n, prot_out, addr_out, size);
> +       err = pmp_get(n, prot_out, addr_out, &log2size);
> +       if (err)
> +               return err;
> +       *size = (log2size < __riscv_xlen) ? 1UL << log2size : 0;
> +
> +       return 0;
>  }
>
>  void sbi_hart_pmp_dump(struct sbi_scratch *scratch)
>  {
> -       unsigned long prot, addr, size;
> +       unsigned long prot, addr, size, log2size;
>         unsigned int i, pmp_count;
>
>         pmp_count = sbi_hart_pmp_count(scratch);
>         for (i = 0; i < pmp_count; i++) {
> -               pmp_get(i, &prot, &addr, &size);
> +               pmp_get(i, &prot, &addr, &log2size);
>                 if (!(prot & PMP_A))
>                         continue;
> +               size = (log2size < __riscv_xlen) ? 1UL << log2size : 0;
>  #if __riscv_xlen == 32
>                 sbi_printf("PMP%d    : 0x%08lx-0x%08lx (A",
>  #else
> @@ -190,18 +199,23 @@ void sbi_hart_pmp_dump(struct sbi_scratch *scratch)
>         }
>  }
>
> -int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long addr,
> +int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch,
> +                           unsigned long addr, unsigned long mode,
>                             unsigned long attr)
>  {
> -       unsigned long prot, size, tempaddr;
> +       unsigned long prot, size, log2size, tempaddr;
>         unsigned int i, pmp_count;
>
>         pmp_count = sbi_hart_pmp_count(scratch);
>         for (i = 0; i < pmp_count; i++) {
> -               pmp_get(i, &prot, &tempaddr, &size);
> +               pmp_get(i, &prot, &tempaddr, &log2size);
>                 if (!(prot & PMP_A))
>                         continue;
> -               if (tempaddr <= addr && addr <= tempaddr + size)
> +               if (mode == PRV_M && !(prot & PMP_L))
> +                       continue;
> +               size = 1UL << log2size;
> +               if ((log2size >= __riscv_xlen) ||
> +                   ((tempaddr <= addr && addr <= tempaddr + size)))
>                         if (!(prot & attr))
>                                 return SBI_EINVALID_ADDR;
>         }
> diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c
> index b430793..8c1b7b0 100644
> --- a/lib/sbi/sbi_hsm.c
> +++ b/lib/sbi/sbi_hsm.c
> @@ -231,7 +231,7 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch, u32 hartid,
>         if (hstate != SBI_HART_STOPPED)
>                 return SBI_EINVAL;
>
> -       rc = sbi_hart_pmp_check_addr(scratch, saddr, PMP_X);
> +       rc = sbi_hart_pmp_check_addr(scratch, saddr, smode, PMP_X);
>         if (rc)
>                 return rc;
>         //TODO: We also need to check saddr for valid physical address as well.
> --
> 2.25.1
>
>
> --
> opensbi mailing list
> opensbi@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/opensbi

LGTM.

Reviewed-by: Atish Patra <atish.patra@wdc.com>
Anup Patel Sept. 16, 2020, 5:31 a.m. UTC | #2
> -----Original Message-----
> From: Atish Patra <atishp@atishpatra.org>
> Sent: 15 September 2020 13:02
> To: Anup Patel <Anup.Patel@wdc.com>
> Cc: Atish Patra <Atish.Patra@wdc.com>; Alistair Francis
> <Alistair.Francis@wdc.com>; Anup Patel <anup@brainfault.org>; OpenSBI
> <opensbi@lists.infradead.org>
> Subject: Re: [PATCH 2/5] lib: sbi: Allow specifying mode in
> sbi_hart_pmp_check_addr() API
> 
> On Wed, Sep 9, 2020 at 7:51 AM Anup Patel <anup.patel@wdc.com> wrote:
> >
> > We extend sbi_hart_pmp_check_addr() API so that users can specify
> > privilege mode of the address for checking PMP access permissions.
> >
> > To achieve this, we end-up converting "unsigned long *size" parameter
> > to "unsigned long *log2len" for pmp_get() implementation so that we
> > can deal with regions of "1UL << __riscv_xlen" size in a special case
> > in sbi_hart_pmp_check_addr() implementation.
> >
> > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > ---
> >  include/sbi/riscv_asm.h |  2 +-
> >  include/sbi/sbi_hart.h  |  3 ++-
> >  lib/sbi/riscv_asm.c     | 18 ++++++++----------
> >  lib/sbi/sbi_hart.c      | 28 +++++++++++++++++++++-------
> >  lib/sbi/sbi_hsm.c       |  2 +-
> >  5 files changed, 33 insertions(+), 20 deletions(-)
> >
> > diff --git a/include/sbi/riscv_asm.h b/include/sbi/riscv_asm.h index
> > 6e093ca..10f31a7 100644
> > --- a/include/sbi/riscv_asm.h
> > +++ b/include/sbi/riscv_asm.h
> > @@ -180,7 +180,7 @@ int pmp_set(unsigned int n, unsigned long prot,
> unsigned long addr,
> >             unsigned long log2len);
> >
> >  int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long
> *addr_out,
> > -           unsigned long *size);
> > +           unsigned long *log2len);
> >
> >  #endif /* !__ASSEMBLY__ */
> >
> > diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h index
> > 1e1eb67..0ba68f0 100644
> > --- a/include/sbi/sbi_hart.h
> > +++ b/include/sbi/sbi_hart.h
> > @@ -42,7 +42,8 @@ int sbi_hart_pmp_get(struct sbi_scratch *scratch,
> unsigned int n,
> >                      unsigned long *prot_out, unsigned long *addr_out,
> >                      unsigned long *size);  void
> > sbi_hart_pmp_dump(struct sbi_scratch *scratch); -int
> > sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long
> > daddr,
> > +int  sbi_hart_pmp_check_addr(struct sbi_scratch *scratch,
> > +                            unsigned long daddr, unsigned long mode,
> >                              unsigned long attr);  bool
> > sbi_hart_has_feature(struct sbi_scratch *scratch, unsigned long
> > feature);  void sbi_hart_get_features_str(struct sbi_scratch *scratch,
> > diff --git a/lib/sbi/riscv_asm.c b/lib/sbi/riscv_asm.c index
> > 799123f..8c54c11 100644
> > --- a/lib/sbi/riscv_asm.c
> > +++ b/lib/sbi/riscv_asm.c
> > @@ -239,16 +239,16 @@ int pmp_set(unsigned int n, unsigned long prot,
> > unsigned long addr,  }
> >
> >  int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long
> *addr_out,
> > -           unsigned long *size)
> > +           unsigned long *log2len)
> >  {
> >         int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr;
> >         unsigned long cfgmask, pmpcfg, prot;
> > -       unsigned long t1, addr, log2len;
> > +       unsigned long t1, addr, len;
> >
> >         /* check parameters */
> > -       if (n >= PMP_COUNT || !prot_out || !addr_out || !size)
> > +       if (n >= PMP_COUNT || !prot_out || !addr_out || !log2len)
> >                 return SBI_EINVAL;
> > -       *prot_out = *addr_out = *size = 0;
> > +       *prot_out = *addr_out = *log2len = 0;
> >
> >         /* calculate PMP register and offset */  #if __riscv_xlen ==
> > 32 @@ -275,23 +275,21 @@ int pmp_get(unsigned int n, unsigned long
> > *prot_out, unsigned long *addr_out,
> >                 addr = csr_read_num(pmpaddr_csr);
> >                 if (addr == -1UL) {
> >                         addr    = 0;
> > -                       log2len = __riscv_xlen;
> > +                       len     = __riscv_xlen;
> >                 } else {
> >                         t1      = ctz(~addr);
> >                         addr    = (addr & ~((1UL << t1) - 1)) << PMP_SHIFT;
> > -                       log2len = (t1 + PMP_SHIFT + 1);
> > +                       len     = (t1 + PMP_SHIFT + 1);
> >                 }
> >         } else {
> >                 addr    = csr_read_num(pmpaddr_csr) << PMP_SHIFT;
> > -               log2len = PMP_SHIFT;
> > +               len     = PMP_SHIFT;
> >         }
> >
> >         /* return details */
> >         *prot_out    = prot;
> >         *addr_out    = addr;
> > -
> > -       if (log2len < __riscv_xlen)
> > -               *size = (1UL << log2len);
> > +       *log2len     = len;
> >
> >         return 0;
> >  }
> > diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c index
> > d788918..4cbe8ce 100644
> > --- a/lib/sbi/sbi_hart.c
> > +++ b/lib/sbi/sbi_hart.c
> > @@ -156,22 +156,31 @@ int sbi_hart_pmp_get(struct sbi_scratch *scratch,
> unsigned int n,
> >                      unsigned long *prot_out, unsigned long *addr_out,
> >                      unsigned long *size)  {
> > +       int err;
> > +       unsigned long log2size;
> > +
> >         if (sbi_hart_pmp_count(scratch) <= n)
> >                 return SBI_EINVAL;
> >
> > -       return pmp_get(n, prot_out, addr_out, size);
> > +       err = pmp_get(n, prot_out, addr_out, &log2size);
> > +       if (err)
> > +               return err;
> > +       *size = (log2size < __riscv_xlen) ? 1UL << log2size : 0;
> > +
> > +       return 0;
> >  }
> >
> >  void sbi_hart_pmp_dump(struct sbi_scratch *scratch)  {
> > -       unsigned long prot, addr, size;
> > +       unsigned long prot, addr, size, log2size;
> >         unsigned int i, pmp_count;
> >
> >         pmp_count = sbi_hart_pmp_count(scratch);
> >         for (i = 0; i < pmp_count; i++) {
> > -               pmp_get(i, &prot, &addr, &size);
> > +               pmp_get(i, &prot, &addr, &log2size);
> >                 if (!(prot & PMP_A))
> >                         continue;
> > +               size = (log2size < __riscv_xlen) ? 1UL << log2size :
> > + 0;
> >  #if __riscv_xlen == 32
> >                 sbi_printf("PMP%d    : 0x%08lx-0x%08lx (A",
> >  #else
> > @@ -190,18 +199,23 @@ void sbi_hart_pmp_dump(struct sbi_scratch
> *scratch)
> >         }
> >  }
> >
> > -int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned
> > long addr,
> > +int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch,
> > +                           unsigned long addr, unsigned long mode,
> >                             unsigned long attr)  {
> > -       unsigned long prot, size, tempaddr;
> > +       unsigned long prot, size, log2size, tempaddr;
> >         unsigned int i, pmp_count;
> >
> >         pmp_count = sbi_hart_pmp_count(scratch);
> >         for (i = 0; i < pmp_count; i++) {
> > -               pmp_get(i, &prot, &tempaddr, &size);
> > +               pmp_get(i, &prot, &tempaddr, &log2size);
> >                 if (!(prot & PMP_A))
> >                         continue;
> > -               if (tempaddr <= addr && addr <= tempaddr + size)
> > +               if (mode == PRV_M && !(prot & PMP_L))
> > +                       continue;
> > +               size = 1UL << log2size;
> > +               if ((log2size >= __riscv_xlen) ||
> > +                   ((tempaddr <= addr && addr <= tempaddr + size)))
> >                         if (!(prot & attr))
> >                                 return SBI_EINVALID_ADDR;
> >         }
> > diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c index
> > b430793..8c1b7b0 100644
> > --- a/lib/sbi/sbi_hsm.c
> > +++ b/lib/sbi/sbi_hsm.c
> > @@ -231,7 +231,7 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
> u32 hartid,
> >         if (hstate != SBI_HART_STOPPED)
> >                 return SBI_EINVAL;
> >
> > -       rc = sbi_hart_pmp_check_addr(scratch, saddr, PMP_X);
> > +       rc = sbi_hart_pmp_check_addr(scratch, saddr, smode, PMP_X);
> >         if (rc)
> >                 return rc;
> >         //TODO: We also need to check saddr for valid physical address as well.
> > --
> > 2.25.1
> >
> >
> > --
> > opensbi mailing list
> > opensbi@lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/opensbi
> 
> LGTM.
> 
> Reviewed-by: Atish Patra <atish.patra@wdc.com>

Applied this patch to the riscv/opensbi repo

Regards,
Anup
diff mbox series

Patch

diff --git a/include/sbi/riscv_asm.h b/include/sbi/riscv_asm.h
index 6e093ca..10f31a7 100644
--- a/include/sbi/riscv_asm.h
+++ b/include/sbi/riscv_asm.h
@@ -180,7 +180,7 @@  int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
 	    unsigned long log2len);
 
 int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
-	    unsigned long *size);
+	    unsigned long *log2len);
 
 #endif /* !__ASSEMBLY__ */
 
diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h
index 1e1eb67..0ba68f0 100644
--- a/include/sbi/sbi_hart.h
+++ b/include/sbi/sbi_hart.h
@@ -42,7 +42,8 @@  int sbi_hart_pmp_get(struct sbi_scratch *scratch, unsigned int n,
 		     unsigned long *prot_out, unsigned long *addr_out,
 		     unsigned long *size);
 void sbi_hart_pmp_dump(struct sbi_scratch *scratch);
-int  sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long daddr,
+int  sbi_hart_pmp_check_addr(struct sbi_scratch *scratch,
+			     unsigned long daddr, unsigned long mode,
 			     unsigned long attr);
 bool sbi_hart_has_feature(struct sbi_scratch *scratch, unsigned long feature);
 void sbi_hart_get_features_str(struct sbi_scratch *scratch,
diff --git a/lib/sbi/riscv_asm.c b/lib/sbi/riscv_asm.c
index 799123f..8c54c11 100644
--- a/lib/sbi/riscv_asm.c
+++ b/lib/sbi/riscv_asm.c
@@ -239,16 +239,16 @@  int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
 }
 
 int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
-	    unsigned long *size)
+	    unsigned long *log2len)
 {
 	int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr;
 	unsigned long cfgmask, pmpcfg, prot;
-	unsigned long t1, addr, log2len;
+	unsigned long t1, addr, len;
 
 	/* check parameters */
-	if (n >= PMP_COUNT || !prot_out || !addr_out || !size)
+	if (n >= PMP_COUNT || !prot_out || !addr_out || !log2len)
 		return SBI_EINVAL;
-	*prot_out = *addr_out = *size = 0;
+	*prot_out = *addr_out = *log2len = 0;
 
 	/* calculate PMP register and offset */
 #if __riscv_xlen == 32
@@ -275,23 +275,21 @@  int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
 		addr = csr_read_num(pmpaddr_csr);
 		if (addr == -1UL) {
 			addr	= 0;
-			log2len = __riscv_xlen;
+			len	= __riscv_xlen;
 		} else {
 			t1	= ctz(~addr);
 			addr	= (addr & ~((1UL << t1) - 1)) << PMP_SHIFT;
-			log2len = (t1 + PMP_SHIFT + 1);
+			len	= (t1 + PMP_SHIFT + 1);
 		}
 	} else {
 		addr	= csr_read_num(pmpaddr_csr) << PMP_SHIFT;
-		log2len = PMP_SHIFT;
+		len	= PMP_SHIFT;
 	}
 
 	/* return details */
 	*prot_out    = prot;
 	*addr_out    = addr;
-
-	if (log2len < __riscv_xlen)
-		*size = (1UL << log2len);
+	*log2len     = len;
 
 	return 0;
 }
diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c
index d788918..4cbe8ce 100644
--- a/lib/sbi/sbi_hart.c
+++ b/lib/sbi/sbi_hart.c
@@ -156,22 +156,31 @@  int sbi_hart_pmp_get(struct sbi_scratch *scratch, unsigned int n,
 		     unsigned long *prot_out, unsigned long *addr_out,
 		     unsigned long *size)
 {
+	int err;
+	unsigned long log2size;
+
 	if (sbi_hart_pmp_count(scratch) <= n)
 		return SBI_EINVAL;
 
-	return pmp_get(n, prot_out, addr_out, size);
+	err = pmp_get(n, prot_out, addr_out, &log2size);
+	if (err)
+		return err;
+	*size = (log2size < __riscv_xlen) ? 1UL << log2size : 0;
+
+	return 0;
 }
 
 void sbi_hart_pmp_dump(struct sbi_scratch *scratch)
 {
-	unsigned long prot, addr, size;
+	unsigned long prot, addr, size, log2size;
 	unsigned int i, pmp_count;
 
 	pmp_count = sbi_hart_pmp_count(scratch);
 	for (i = 0; i < pmp_count; i++) {
-		pmp_get(i, &prot, &addr, &size);
+		pmp_get(i, &prot, &addr, &log2size);
 		if (!(prot & PMP_A))
 			continue;
+		size = (log2size < __riscv_xlen) ? 1UL << log2size : 0;
 #if __riscv_xlen == 32
 		sbi_printf("PMP%d    : 0x%08lx-0x%08lx (A",
 #else
@@ -190,18 +199,23 @@  void sbi_hart_pmp_dump(struct sbi_scratch *scratch)
 	}
 }
 
-int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long addr,
+int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch,
+			    unsigned long addr, unsigned long mode,
 			    unsigned long attr)
 {
-	unsigned long prot, size, tempaddr;
+	unsigned long prot, size, log2size, tempaddr;
 	unsigned int i, pmp_count;
 
 	pmp_count = sbi_hart_pmp_count(scratch);
 	for (i = 0; i < pmp_count; i++) {
-		pmp_get(i, &prot, &tempaddr, &size);
+		pmp_get(i, &prot, &tempaddr, &log2size);
 		if (!(prot & PMP_A))
 			continue;
-		if (tempaddr <= addr && addr <= tempaddr + size)
+		if (mode == PRV_M && !(prot & PMP_L))
+			continue;
+		size = 1UL << log2size;
+		if ((log2size >= __riscv_xlen) ||
+		    ((tempaddr <= addr && addr <= tempaddr + size)))
 			if (!(prot & attr))
 				return SBI_EINVALID_ADDR;
 	}
diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c
index b430793..8c1b7b0 100644
--- a/lib/sbi/sbi_hsm.c
+++ b/lib/sbi/sbi_hsm.c
@@ -231,7 +231,7 @@  int sbi_hsm_hart_start(struct sbi_scratch *scratch, u32 hartid,
 	if (hstate != SBI_HART_STOPPED)
 		return SBI_EINVAL;
 
-	rc = sbi_hart_pmp_check_addr(scratch, saddr, PMP_X);
+	rc = sbi_hart_pmp_check_addr(scratch, saddr, smode, PMP_X);
 	if (rc)
 		return rc;
 	//TODO: We also need to check saddr for valid physical address as well.