From: Gabriel Gama <operatingsystemsdepression@gmail.com>
To: dri-devel@lists.freedesktop.org
Cc: patrik.r.jakobsson@gmail.com
Subject: [RFC PATCH v2 4/6] drm/gma500: Make SGX MMU insertion checked and transactional
Date: Mon, 9 Nov 2026 03:33:01 -0300 [thread overview]
Message-ID: <20261109063303.32658-5-operatingsystemsdepression@gmail.com> (raw)
In-Reply-To: <20261109063303.32658-1-operatingsystemsdepression@gmail.com>
Validate 32-bit mapping extents, PFNs and tiled geometry before changing
PTEs. Serialize changes with the write semaphore and undo only the
inserted prefix on allocation failure or collision, preserving existing
entries. Do not allocate tables or decrement counts when removing holes.
Use 64-bit exclusive endpoints so mapping the last GPU page does not wrap
on i386. Zero-page requests remain no-ops.
Signed-off-by: Gabriel Gama <operatingsystemsdepression@gmail.com>
---
drivers/gpu/drm/gma500/mmu.c | 211 +++++++++++++++++++++++++----------
drivers/gpu/drm/gma500/mmu.h | 5 +-
2 files changed, 158 insertions(+), 58 deletions(-)
diff --git a/drivers/gpu/drm/gma500/mmu.c b/drivers/gpu/drm/gma500/mmu.c
index 34ae0f125..0d98c7870 100644
--- a/drivers/gpu/drm/gma500/mmu.c
+++ b/drivers/gpu/drm/gma500/mmu.c
@@ -136,10 +136,9 @@ void psb_mmu_set_pd_context(struct psb_mmu_pd *pd, int hw_context)
}
-static inline unsigned long psb_pd_addr_end(unsigned long addr,
- unsigned long end)
+static inline u64 psb_pd_addr_end(u64 addr, u64 end)
{
- addr = (addr + PSB_PDE_MASK + 1) & ~PSB_PDE_MASK;
+ addr = (addr + PSB_PDE_MASK + 1) & ~(u64)PSB_PDE_MASK;
return (addr < end) ? addr : end;
}
@@ -484,13 +483,13 @@ static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, unsigned long address,
struct psb_mmu_pt *pt;
uint32_t rows = 1;
uint32_t i;
- unsigned long addr;
- unsigned long end;
- unsigned long next;
- unsigned long add;
- unsigned long row_add;
+ u64 addr;
+ u64 end;
+ u64 next;
+ u64 add;
+ u64 row_add;
unsigned long clflush_add = pd->driver->clflush_add;
- unsigned long clflush_mask = pd->driver->clflush_mask;
+ u64 clflush_mask = ~((u64)clflush_add - 1);
if (!pd->driver->has_clflush)
return;
@@ -500,8 +499,8 @@ static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, unsigned long address,
else
desired_tile_stride = num_pages;
- add = desired_tile_stride << PAGE_SHIFT;
- row_add = hw_tile_stride << PAGE_SHIFT;
+ add = (u64)desired_tile_stride << PAGE_SHIFT;
+ row_add = (u64)hw_tile_stride << PAGE_SHIFT;
mb();
for (i = 0; i < rows; ++i) {
@@ -525,38 +524,97 @@ static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, unsigned long address,
mb();
}
+/* Validate the complete mapping before touching page tables. */
+static int psb_mmu_check_range(unsigned long address, u32 num_pages,
+ u32 desired_tile_stride, u32 hw_tile_stride)
+{
+ u64 span;
+ u32 rows;
+
+ if (!IS_ALIGNED(address, PAGE_SIZE))
+ return -EINVAL;
+ if (((u64)address >> 32) || num_pages > BIT(20))
+ return -ERANGE;
+ if (!num_pages)
+ return 0;
+
+ if (hw_tile_stride) {
+ if (!desired_tile_stride ||
+ num_pages % desired_tile_stride ||
+ hw_tile_stride < desired_tile_stride)
+ return -EINVAL;
+ rows = num_pages / desired_tile_stride;
+ span = (u64)(rows - 1) * hw_tile_stride + desired_tile_stride;
+ } else {
+ span = num_pages;
+ }
+
+ if (span > (BIT_ULL(32) - address) >> PAGE_SHIFT)
+ return -ERANGE;
+
+ return 0;
+}
+
+/* The caller holds driver->sem for write; only its inserted prefix is undone. */
+static void psb_mmu_rollback_pages(struct psb_mmu_pd *pd,
+ unsigned long address, u32 inserted,
+ u32 desired_tile_stride, u32 hw_tile_stride)
+{
+ struct psb_mmu_pt *pt;
+ u64 offset;
+ u32 i;
+
+ for (i = 0; i < inserted; i++) {
+ if (hw_tile_stride)
+ offset = (u64)(i / desired_tile_stride) * hw_tile_stride +
+ i % desired_tile_stride;
+ else
+ offset = i;
+ pt = psb_mmu_pt_map_lock(pd, address + (offset << PAGE_SHIFT));
+ if (WARN_ON_ONCE(!pt))
+ continue;
+ psb_mmu_invalidate_pte(pt, address + (offset << PAGE_SHIFT));
+ pt->count--;
+ psb_mmu_pt_unmap_unlock(pt);
+ }
+}
+
void psb_mmu_remove_pfn_sequence(struct psb_mmu_pd *pd,
unsigned long address, uint32_t num_pages)
{
struct psb_mmu_pt *pt;
- unsigned long addr;
- unsigned long end;
- unsigned long next;
+ u64 addr;
+ u64 end;
+ u64 next;
unsigned long f_address = address;
- down_read(&pd->driver->sem);
+ if (!num_pages || psb_mmu_check_range(address, num_pages, 0, 0))
+ return;
+
+ down_write(&pd->driver->sem);
addr = address;
- end = addr + (num_pages << PAGE_SHIFT);
+ end = addr + ((u64)num_pages << PAGE_SHIFT);
do {
next = psb_pd_addr_end(addr, end);
- pt = psb_mmu_pt_alloc_map_lock(pd, addr);
+ pt = psb_mmu_pt_map_lock(pd, addr);
if (!pt)
- goto out;
+ continue;
do {
- psb_mmu_invalidate_pte(pt, addr);
- --pt->count;
+ if (pt->v[psb_mmu_pt_index(addr)] != pd->invalid_pte) {
+ psb_mmu_invalidate_pte(pt, addr);
+ --pt->count;
+ }
} while (addr += PAGE_SIZE, addr < next);
psb_mmu_pt_unmap_unlock(pt);
} while (addr = next, next != end);
-out:
if (pd->hw_context != -1)
psb_mmu_flush_ptes(pd, f_address, num_pages, 1, 1);
- up_read(&pd->driver->sem);
+ up_write(&pd->driver->sem);
if (pd->hw_context != -1)
psb_mmu_flush(pd->driver);
@@ -571,22 +629,26 @@ void psb_mmu_remove_pages(struct psb_mmu_pd *pd, unsigned long address,
struct psb_mmu_pt *pt;
uint32_t rows = 1;
uint32_t i;
- unsigned long addr;
- unsigned long end;
- unsigned long next;
- unsigned long add;
- unsigned long row_add;
+ u64 addr;
+ u64 end;
+ u64 next;
+ u64 add;
+ u64 row_add;
unsigned long f_address = address;
+ if (!num_pages || psb_mmu_check_range(address, num_pages,
+ desired_tile_stride, hw_tile_stride))
+ return;
+
if (hw_tile_stride)
rows = num_pages / desired_tile_stride;
else
desired_tile_stride = num_pages;
- add = desired_tile_stride << PAGE_SHIFT;
- row_add = hw_tile_stride << PAGE_SHIFT;
+ add = (u64)desired_tile_stride << PAGE_SHIFT;
+ row_add = (u64)hw_tile_stride << PAGE_SHIFT;
- down_read(&pd->driver->sem);
+ down_write(&pd->driver->sem);
/* Make sure we only need to flush this processor's cache */
@@ -601,8 +663,10 @@ void psb_mmu_remove_pages(struct psb_mmu_pd *pd, unsigned long address,
if (!pt)
continue;
do {
- psb_mmu_invalidate_pte(pt, addr);
- --pt->count;
+ if (pt->v[psb_mmu_pt_index(addr)] != pd->invalid_pte) {
+ psb_mmu_invalidate_pte(pt, addr);
+ --pt->count;
+ }
} while (addr += PAGE_SIZE, addr < next);
psb_mmu_pt_unmap_unlock(pt);
@@ -614,7 +678,7 @@ void psb_mmu_remove_pages(struct psb_mmu_pd *pd, unsigned long address,
psb_mmu_flush_ptes(pd, f_address, num_pages,
desired_tile_stride, hw_tile_stride);
- up_read(&pd->driver->sem);
+ up_write(&pd->driver->sem);
if (pd->hw_context != -1)
psb_mmu_flush(pd->driver);
@@ -626,16 +690,23 @@ int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd, uint32_t start_pfn,
{
struct psb_mmu_pt *pt;
uint32_t pte;
- unsigned long addr;
- unsigned long end;
- unsigned long next;
+ u64 addr;
+ u64 end;
+ u64 next;
unsigned long f_address = address;
- int ret = -ENOMEM;
+ u32 inserted = 0;
+ int ret;
+
+ ret = psb_mmu_check_range(address, num_pages, 0, 0);
+ if (ret || !num_pages)
+ return ret;
+ if ((u64)start_pfn + num_pages > BIT_ULL(20))
+ return -ERANGE;
- down_read(&pd->driver->sem);
+ down_write(&pd->driver->sem);
addr = address;
- end = addr + (num_pages << PAGE_SHIFT);
+ end = addr + ((u64)num_pages << PAGE_SHIFT);
do {
next = psb_pd_addr_end(addr, end);
@@ -645,9 +716,15 @@ int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd, uint32_t start_pfn,
goto out;
}
do {
+ if (pt->v[psb_mmu_pt_index(addr)] != pd->invalid_pte) {
+ psb_mmu_pt_unmap_unlock(pt);
+ ret = -EBUSY;
+ goto out;
+ }
pte = psb_mmu_mask_pte(start_pfn++, type);
psb_mmu_set_pte(pt, addr, pte);
pt->count++;
+ inserted++;
} while (addr += PAGE_SIZE, addr < next);
psb_mmu_pt_unmap_unlock(pt);
@@ -655,10 +732,12 @@ int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd, uint32_t start_pfn,
ret = 0;
out:
+ if (ret)
+ psb_mmu_rollback_pages(pd, f_address, inserted, 0, 0);
if (pd->hw_context != -1)
psb_mmu_flush_ptes(pd, f_address, num_pages, 1, 1);
- up_read(&pd->driver->sem);
+ up_write(&pd->driver->sem);
if (pd->hw_context != -1)
psb_mmu_flush(pd->driver);
@@ -675,26 +754,35 @@ int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages,
uint32_t rows = 1;
uint32_t i;
uint32_t pte;
- unsigned long addr;
- unsigned long end;
- unsigned long next;
- unsigned long add;
- unsigned long row_add;
+ u64 addr;
+ u64 end;
+ u64 next;
+ u64 add;
+ u64 row_add;
unsigned long f_address = address;
- int ret = -ENOMEM;
+ u32 inserted = 0;
+ int ret;
+
+ ret = psb_mmu_check_range(address, num_pages,
+ desired_tile_stride, hw_tile_stride);
+ if (ret || !num_pages)
+ return ret;
+ if (!pages)
+ return -EINVAL;
+ for (i = 0; i < num_pages; i++) {
+ if (!pages[i] || page_to_pfn(pages[i]) >= BIT_ULL(20))
+ return -ERANGE;
+ }
- if (hw_tile_stride) {
- if (num_pages % desired_tile_stride != 0)
- return -EINVAL;
+ if (hw_tile_stride)
rows = num_pages / desired_tile_stride;
- } else {
+ else
desired_tile_stride = num_pages;
- }
- add = desired_tile_stride << PAGE_SHIFT;
- row_add = hw_tile_stride << PAGE_SHIFT;
+ add = (u64)desired_tile_stride << PAGE_SHIFT;
+ row_add = (u64)hw_tile_stride << PAGE_SHIFT;
- down_read(&pd->driver->sem);
+ down_write(&pd->driver->sem);
for (i = 0; i < rows; ++i) {
@@ -704,13 +792,21 @@ int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages,
do {
next = psb_pd_addr_end(addr, end);
pt = psb_mmu_pt_alloc_map_lock(pd, addr);
- if (!pt)
+ if (!pt) {
+ ret = -ENOMEM;
goto out;
+ }
do {
+ if (pt->v[psb_mmu_pt_index(addr)] != pd->invalid_pte) {
+ psb_mmu_pt_unmap_unlock(pt);
+ ret = -EBUSY;
+ goto out;
+ }
pte = psb_mmu_mask_pte(page_to_pfn(*pages++),
type);
psb_mmu_set_pte(pt, addr, pte);
pt->count++;
+ inserted++;
} while (addr += PAGE_SIZE, addr < next);
psb_mmu_pt_unmap_unlock(pt);
@@ -721,11 +817,14 @@ int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages,
ret = 0;
out:
+ if (ret)
+ psb_mmu_rollback_pages(pd, f_address, inserted, desired_tile_stride,
+ hw_tile_stride);
if (pd->hw_context != -1)
psb_mmu_flush_ptes(pd, f_address, num_pages,
desired_tile_stride, hw_tile_stride);
- up_read(&pd->driver->sem);
+ up_write(&pd->driver->sem);
if (pd->hw_context != -1)
psb_mmu_flush(pd->driver);
diff --git a/drivers/gpu/drm/gma500/mmu.h b/drivers/gpu/drm/gma500/mmu.h
index e6d397037..4474718aa 100644
--- a/drivers/gpu/drm/gma500/mmu.h
+++ b/drivers/gpu/drm/gma500/mmu.h
@@ -9,8 +9,9 @@
#define __MMU_H
struct psb_mmu_driver {
- /* protects driver- and pd structures. Always take in read mode
- * before taking the page table spinlock.
+ /*
+ * Protects driver and page-directory structures. Mapping changes take
+ * this semaphore for write, before the page-table spinlock.
*/
struct rw_semaphore sem;
next prev parent reply other threads:[~2026-11-09 6:33 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-09 6:32 [RFC PATCH v2 0/6] drm/gma500: prepare GEM and MMU for 3D rendering and hybrid 2D Gabriel Gama
2026-11-09 6:32 ` [RFC PATCH v2 1/6] drm/gma500: use the common dumb-buffer size helper Gabriel Gama
2026-11-12 21:20 ` Joseph Telaak
2026-11-09 6:32 ` [RFC PATCH v2 2/6] drm/gma500: do not underflow an unpinned GEM object Gabriel Gama
2026-11-12 21:17 ` Joseph Telaak
2026-11-09 6:33 ` [RFC PATCH v2 3/6] drm/gma500: Fix SGX page-table cache-flush mapping lifetime Gabriel Gama
2026-11-12 21:20 ` Joseph Telaak
2026-11-09 6:33 ` Gabriel Gama [this message]
2026-11-09 6:41 ` [RFC PATCH v2 4/6] drm/gma500: Make SGX MMU insertion checked and transactional sashiko-bot
2026-11-12 21:20 ` Joseph Telaak
2026-11-09 6:33 ` [RFC PATCH v2 5/6] drm/gma500: Propagate SGX MMU setup and GEM pin failures Gabriel Gama
2026-11-12 21:20 ` Joseph Telaak
2026-11-13 2:17 ` Gabriel Gama
2026-11-09 6:33 ` [RFC PATCH v2 6/6] drm/gma500: Add software-only KUnit coverage for SGX page tables Gabriel Gama
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261109063303.32658-5-operatingsystemsdepression@gmail.com \
--to=operatingsystemsdepression@gmail.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=patrik.r.jakobsson@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.