summaryrefslogtreecommitdiff
path: root/arch/um
diff options
context:
space:
mode:
authorBenjamin Berg <benjamin.berg@intel.com>2024-07-03 15:45:29 +0200
committerJohannes Berg <johannes.berg@intel.com>2024-07-03 17:09:49 +0200
commit6d8992e49e2aed3ee2d73b88050f40f26ae6bf86 (patch)
treeaa72a8731989ea47256331e6b81ea95dfc942ac5 /arch/um
parent76ed9158e1d474e963fc59da7a461b27a2212c5a (diff)
um: compress memory related stub syscalls while adding them
To keep the number of syscalls that the stub has to do lower, compress two consecutive syscalls of the same type if the second is just a continuation of the first. Signed-off-by: Benjamin Berg <benjamin.berg@intel.com> Link: https://patch.msgid.link/20240703134536.1161108-6-benjamin@sipsolutions.net Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'arch/um')
-rw-r--r--arch/um/os-Linux/skas/mem.c39
1 files changed, 39 insertions, 0 deletions
diff --git a/arch/um/os-Linux/skas/mem.c b/arch/um/os-Linux/skas/mem.c
index 40be9085f65b..32c61189110c 100644
--- a/arch/um/os-Linux/skas/mem.c
+++ b/arch/um/os-Linux/skas/mem.c
@@ -151,12 +151,37 @@ struct stub_syscall *syscall_stub_alloc(struct mm_id *mm_idp)
return sc;
}
+static struct stub_syscall *syscall_stub_get_previous(struct mm_id *mm_idp,
+ int syscall_type,
+ unsigned long virt)
+{
+ if (mm_idp->syscall_data_len > 0) {
+ struct stub_data *proc_data = (void *) mm_idp->stack;
+ struct stub_syscall *sc;
+
+ sc = &proc_data->syscall_data[mm_idp->syscall_data_len - 1];
+
+ if (sc->syscall == syscall_type &&
+ sc->mem.addr + sc->mem.length == virt)
+ return sc;
+ }
+
+ return NULL;
+}
void map(struct mm_id *mm_idp, unsigned long virt, unsigned long len, int prot,
int phys_fd, unsigned long long offset)
{
struct stub_syscall *sc;
+ /* Compress with previous syscall if that is possible */
+ sc = syscall_stub_get_previous(mm_idp, STUB_SYSCALL_MMAP, virt);
+ if (sc && sc->mem.prot == prot && sc->mem.fd == phys_fd &&
+ sc->mem.offset == MMAP_OFFSET(offset - sc->mem.length)) {
+ sc->mem.length += len;
+ return;
+ }
+
sc = syscall_stub_alloc(mm_idp);
sc->syscall = STUB_SYSCALL_MMAP;
sc->mem.addr = virt;
@@ -170,6 +195,13 @@ void unmap(struct mm_id *mm_idp, unsigned long addr, unsigned long len)
{
struct stub_syscall *sc;
+ /* Compress with previous syscall if that is possible */
+ sc = syscall_stub_get_previous(mm_idp, STUB_SYSCALL_MUNMAP, addr);
+ if (sc) {
+ sc->mem.length += len;
+ return;
+ }
+
sc = syscall_stub_alloc(mm_idp);
sc->syscall = STUB_SYSCALL_MUNMAP;
sc->mem.addr = addr;
@@ -181,6 +213,13 @@ void protect(struct mm_id *mm_idp, unsigned long addr, unsigned long len,
{
struct stub_syscall *sc;
+ /* Compress with previous syscall if that is possible */
+ sc = syscall_stub_get_previous(mm_idp, STUB_SYSCALL_MPROTECT, addr);
+ if (sc && sc->mem.prot == prot) {
+ sc->mem.length += len;
+ return;
+ }
+
sc = syscall_stub_alloc(mm_idp);
sc->syscall = STUB_SYSCALL_MPROTECT;
sc->mem.addr = addr;