# HG changeset patch
# User jfp <jf.pieronne@laposte.net>
# Date 1737965165 -3600
#      Mon Jan 27 09:06:05 2025 +0100
# Node ID 56bdbeabb0c4c8500eaaae1c4063e1f40ec7e2a1
# Parent  6e0b22f464a6cebb092c4e0c3a31d83c5e6376dd
Allocate buffer with a end at page limit

diff --git a/python/local/ovms_module/ovms/ptd/_vmsptd.pyx b/python/local/ovms_module/ovms/ptd/_vmsptd.pyx
--- a/python/local/ovms_module/ovms/ptd/_vmsptd.pyx
+++ b/python/local/ovms_module/ovms/ptd/_vmsptd.pyx
@@ -112,7 +112,8 @@
     void read_start_read_ast (...)
     void read_end_read_ast (...)
     void* align_pointer (...)
-
+    void* allocate_page_aligned_memory(...)
+    void free_page_aligned_memory(...)
 
 from libc.stdio cimport printf, puts, sprintf
                   
@@ -302,22 +303,21 @@
     cdef  PtdHandler handler = PtdHandler()
     cdef DevChar* devchar
     cdef unsigned short buflen
-    cdef int item_code = SYI__MAXBUF 
+    cdef int item_code = SYI__MAXBUF
     cdef int maxbuf
     s = lib_getsyi(&item_code, &maxbuf)
+    checkStatus(s);
     cdef int nbpages = 6 # 4 + 1 data + 1 guard pages
     cdef int nbpagelets = <int>(nbpages * pgsize / 512)
-
-    checkStatus(s);
+    cdef int allocsz = sizeof(ptd_handler) + 3 * maxbuf + pgsize
     if charbuff is None:
         devchar = NULL
         buflen = 0
     else:
         devchar = &(charbuff.devchar)
         buflen = sizeof(charbuff.devchar)
-    s = lib_get_vm_page(&nbpagelets, &(handler.handler))
-    checkStatus(s)
-    ptrc = <char *>align_pointer(<char *>handler.handler + pgsize, pgsize, 1) # align to page boundary, keep one data page
+    handler.handler = <ptd_handler *>allocate_page_aligned_memory(allocsz, pgsize)
+    ptrc = <char *>handler.handler + pgsize
     handler.handler.read_buf = ptrc
     handler.handler.write_buf = ptrc + maxbuf
     handler.handler.echo_buf = ptrc + 2 * maxbuf
@@ -325,22 +325,20 @@
     handler.handler.maxbuf = maxbuf
     handler.handler.inadr.va_range_ps_start_va = ptrc
     handler.handler.buflen = buflen
-    handler.handler.inadr.va_range_ps_end_va = <char *>align_pointer(<char *>handler.handler + nbpagelets * 512 - 1, 
-                                                                     pgsize, 0) - 1
+    handler.handler.inadr.va_range_ps_end_va = \
+        <char *>align_pointer(<char *>handler.handler + allocsz, pgsize, 1) - 1
     handler.handler.read_status = 0
     handler.handler.timer_status = 0
     s = lib_get_ef(<unsigned int *>&(handler.handler.efn))
     if s & 1 == 0:
-        lib_free_vm_page(<int *>&(handler.handler.nbpagelets),
-                         &(handler.handler))
+        free_page_aligned_memory(ptrc)
     checkStatus(s)
     s = ptd_create(<unsigned short*>&(handler.handler.channel), acmode,
                    devchar, buflen, 0, 0, 0,
                    <VA_RANGE *>&(handler.handler.inadr))
     if s & 1 == 0:
         lib_free_ef(<unsigned int *>&(handler.handler.efn))
-        lib_free_vm_page(<int *>&(handler.handler.nbpagelets),
-                         &(handler.handler))        
+        free_page_aligned_memory(ptrc)
     checkStatus(s)
     return s, handler
 
@@ -353,8 +351,7 @@
     checkStatus(s)
     s = lib_free_ef(<unsigned int *>&(handler.handler.efn))
     checkStatus(s)
-    s = lib_free_vm_page(<int *>&(handler.handler.nbpagelets),
-                         &(handler.handler))
+    free_page_aligned_memory(handler.handler.read_buf)
     return s
 
 def readw(PtdHandler handler):
diff --git a/python/local/ovms_module/ovms/ptd/ovptd.h b/python/local/ovms_module/ovms/ptd/ovptd.h
--- a/python/local/ovms_module/ovms/ptd/ovptd.h
+++ b/python/local/ovms_module/ovms/ptd/ovptd.h
@@ -166,4 +166,51 @@
         return (void*)(addr & ~(page_size - 1));
     }
 }
+
+void* allocate_page_aligned_memory(size_t size, size_t page_size) {
+    /*
+     * Allocates memory aligned to a page boundary with a length rounded
+     * to the nearest multiple of the page size.
+     *
+     * Parameters:
+     *   size      - The requested size of the memory block.
+     *   page_size - The alignment size (usually the system's page size).
+     *
+     * Returns:
+     *   A pointer to the allocated memory (aligned) or NULL on failure.
+     */
+
+    // Round size up to the nearest multiple of the page size
+    size_t rounded_size = (size + page_size - 1) & ~(page_size - 1);
+
+    // Over-allocate memory to ensure alignment
+    void* raw_memory = malloc(rounded_size + page_size - 1 + sizeof(void*));
+    if (raw_memory == NULL) {
+        return NULL; // Allocation failed
+    }
+
+    // Align the pointer
+    uintptr_t raw_addr = (uintptr_t)raw_memory + sizeof(void*);
+    uintptr_t aligned_addr = (raw_addr + (page_size - 1)) & ~(page_size - 1);
+
+    // Store the original pointer just before the aligned memory
+    ((void**)aligned_addr)[-1] = raw_memory;
+
+    return (void*)aligned_addr;
+}
+
+void free_page_aligned_memory(void* aligned_memory) {
+    /*
+     * Frees memory allocated with allocate_page_aligned_memory.
+     *
+     * Parameters:
+     *   aligned_memory - Pointer to the aligned memory.
+     */
+    if (aligned_memory) {
+        // Retrieve the original pointer and free it
+        void* raw_memory = ((void**)aligned_memory)[-1];
+        free(raw_memory);
+    }
+}
+
 #endif