gdb support for user mode (Paul Brook)
[qemu] / exec.c
diff --git a/exec.c b/exec.c
index 95883be..f923043 100644 (file)
--- a/exec.c
+++ b/exec.c
@@ -21,6 +21,7 @@
 #ifdef _WIN32
 #include <windows.h>
 #else
+#include <sys/types.h>
 #include <sys/mman.h>
 #endif
 #include <stdlib.h>
@@ -57,7 +58,7 @@ int nb_tbs;
 /* any access to the tbs or the page table must use this lock */
 spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
 
-uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
+uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE] __attribute__((aligned (32)));
 uint8_t *code_gen_ptr;
 
 int phys_ram_size;
@@ -109,7 +110,7 @@ unsigned long qemu_host_page_mask;
 
 /* XXX: for system emulation, it could just be an array */
 static PageDesc *l1_map[L1_SIZE];
-static PhysPageDesc *l1_phys_map[L1_SIZE];
+PhysPageDesc **l1_phys_map;
 
 #if !defined(CONFIG_USER_ONLY)
 static VirtPageDesc *l1_virt_map[L1_SIZE];
@@ -127,6 +128,11 @@ char *logfilename = "/tmp/qemu.log";
 FILE *logfile;
 int loglevel;
 
+/* statistics */
+static int tlb_flush_count;
+static int tb_flush_count;
+static int tb_phys_invalidate_count;
+
 static void page_init(void)
 {
     /* NOTE: we can always suppose that qemu_host_page_size >=
@@ -170,6 +176,8 @@ static void page_init(void)
 #if !defined(CONFIG_USER_ONLY)
     virt_valid_tag = 1;
 #endif
+    l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(PhysPageDesc *));
+    memset(l1_phys_map, 0, L1_SIZE * sizeof(PhysPageDesc *));
 }
 
 static inline PageDesc *page_find_alloc(unsigned int index)
@@ -205,7 +213,7 @@ static inline PhysPageDesc *phys_page_find_alloc(unsigned int index)
     p = *lp;
     if (!p) {
         /* allocate if not found */
-        p = qemu_malloc(sizeof(PhysPageDesc) * L2_SIZE);
+        p = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
         memset(p, 0, sizeof(PhysPageDesc) * L2_SIZE);
         *lp = p;
     }
@@ -230,6 +238,10 @@ static inline VirtPageDesc *virt_page_find_alloc(unsigned int index)
 {
     VirtPageDesc **lp, *p;
 
+    /* XXX: should not truncate for 64 bit addresses */
+#if TARGET_LONG_BITS > 32
+    index &= (L1_SIZE - 1);
+#endif
     lp = &l1_virt_map[index >> L2_BITS];
     p = *lp;
     if (!p) {
@@ -331,6 +343,7 @@ void tb_flush(CPUState *env)
     code_gen_ptr = code_gen_buffer;
     /* XXX: flush processor icache at this point if cache flush is
        expensive */
+    tb_flush_count++;
 }
 
 #ifdef DEBUG_TB_CHECK
@@ -525,6 +538,7 @@ static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_ad
     }
 
     tb_invalidate(tb);
+    tb_phys_invalidate_count++;
 }
 
 static inline void set_bits(uint8_t *tab, int start, int len)
@@ -596,13 +610,13 @@ static void tb_gen_code(CPUState *env,
     target_ulong phys_pc, phys_page2, virt_page2;
     int code_gen_size;
 
-    phys_pc = get_phys_addr_code(env, (unsigned long)pc);
-    tb = tb_alloc((unsigned long)pc);
+    phys_pc = get_phys_addr_code(env, pc);
+    tb = tb_alloc(pc);
     if (!tb) {
         /* flush must be done */
         tb_flush(env);
         /* cannot fail at this point */
-        tb = tb_alloc((unsigned long)pc);
+        tb = tb_alloc(pc);
     }
     tc_ptr = code_gen_ptr;
     tb->tc_ptr = tc_ptr;
@@ -613,9 +627,9 @@ static void tb_gen_code(CPUState *env,
     code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
     
     /* check next page if needed */
-    virt_page2 = ((unsigned long)pc + tb->size - 1) & TARGET_PAGE_MASK;
+    virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
     phys_page2 = -1;
-    if (((unsigned long)pc & TARGET_PAGE_MASK) != virt_page2) {
+    if ((pc & TARGET_PAGE_MASK) != virt_page2) {
         phys_page2 = get_phys_addr_code(env, virt_page2);
     }
     tb_link_phys(tb, phys_pc, phys_page2);
@@ -883,7 +897,7 @@ static inline void tb_alloc_page(TranslationBlock *tb,
 
 /* Allocate a new translation block. Flush the translation buffer if
    too many translation blocks or too much generated code. */
-TranslationBlock *tb_alloc(unsigned long pc)
+TranslationBlock *tb_alloc(target_ulong pc)
 {
     TranslationBlock *tb;
 
@@ -1062,6 +1076,7 @@ static void tb_reset_jump_recursive(TranslationBlock *tb)
     tb_reset_jump_recursive2(tb, 1);
 }
 
+#if defined(TARGET_HAS_ICE)
 static void breakpoint_invalidate(CPUState *env, target_ulong pc)
 {
     target_ulong phys_addr;
@@ -1069,12 +1084,13 @@ static void breakpoint_invalidate(CPUState *env, target_ulong pc)
     phys_addr = cpu_get_phys_page_debug(env, pc);
     tb_invalidate_phys_page_range(phys_addr, phys_addr + 1, 0);
 }
+#endif
 
 /* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
    breakpoint is reached */
 int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
 {
-#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
+#if defined(TARGET_HAS_ICE)
     int i;
     
     for(i = 0; i < env->nb_breakpoints; i++) {
@@ -1096,7 +1112,7 @@ int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
 /* remove a breakpoint */
 int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
 {
-#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
+#if defined(TARGET_HAS_ICE)
     int i;
     for(i = 0; i < env->nb_breakpoints; i++) {
         if (env->breakpoints[i] == pc)
@@ -1104,9 +1120,9 @@ int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
     }
     return -1;
  found:
-    memmove(&env->breakpoints[i], &env->breakpoints[i + 1],
-            (env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0]));
     env->nb_breakpoints--;
+    if (i < env->nb_breakpoints)
+      env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
 
     breakpoint_invalidate(env, pc);
     return 0;
@@ -1119,7 +1135,7 @@ int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
    CPU loop after each instruction */
 void cpu_single_step(CPUState *env, int enabled)
 {
-#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
+#if defined(TARGET_HAS_ICE)
     if (env->singlestep_enabled != enabled) {
         env->singlestep_enabled = enabled;
         /* must flush all the translated code to avoid inconsistancies */
@@ -1291,6 +1307,12 @@ void tlb_flush(CPUState *env, int flush_global)
 #if !defined(CONFIG_SOFTMMU)
     munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
 #endif
+#ifdef USE_KQEMU
+    if (env->kqemu_enabled) {
+        kqemu_flush(env, flush_global);
+    }
+#endif
+    tlb_flush_count++;
 }
 
 static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
@@ -1347,6 +1369,11 @@ void tlb_flush_page(CPUState *env, target_ulong addr)
     if (addr < MMAP_AREA_END)
         munmap((void *)addr, TARGET_PAGE_SIZE);
 #endif
+#ifdef USE_KQEMU
+    if (env->kqemu_enabled) {
+        kqemu_flush_page(env, addr);
+    }
+#endif
 }
 
 static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, target_ulong addr)
@@ -1411,11 +1438,13 @@ static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
     }
 }
 
-void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end)
+void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end,
+                                     int dirty_flags)
 {
     CPUState *env;
     unsigned long length, start1;
-    int i;
+    int i, mask, len;
+    uint8_t *p;
 
     start &= TARGET_PAGE_MASK;
     end = TARGET_PAGE_ALIGN(end);
@@ -1423,7 +1452,11 @@ void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end)
     length = end - start;
     if (length == 0)
         return;
-    memset(phys_ram_dirty + (start >> TARGET_PAGE_BITS), 0, length >> TARGET_PAGE_BITS);
+    mask = ~dirty_flags;
+    p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
+    len = length >> TARGET_PAGE_BITS;
+    for(i = 0; i < len; i++)
+        p[i] &= mask;
 
     env = cpu_single_env;
     /* we modify the TLB cache so that the dirty bit will be set again
@@ -1482,7 +1515,7 @@ static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
     CPUState *env = cpu_single_env;
     int i;
 
-    phys_ram_dirty[(addr - (unsigned long)phys_ram_base) >> TARGET_PAGE_BITS] = 1;
+    phys_ram_dirty[(addr - (unsigned long)phys_ram_base) >> TARGET_PAGE_BITS] = 0xff;
 
     addr &= TARGET_PAGE_MASK;
     i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
@@ -1654,7 +1687,7 @@ int page_unprotect(unsigned long addr, unsigned long pc, void *puc)
         cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n",
                   (unsigned long)addr, vp->prot);
     /* set the dirty bit */
-    phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 1;
+    phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 0xff;
     /* flush the code inside */
     tb_invalidate_phys_page(vp->phys_addr, pc, puc);
     return 1;
@@ -1871,8 +1904,8 @@ static void code_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
 #if !defined(CONFIG_USER_ONLY)
     tb_invalidate_phys_page_fast(phys_addr, 1);
 #endif
-    stb_raw((uint8_t *)addr, val);
-    phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
+    stb_p((uint8_t *)(long)addr, val);
+    phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 0xff;
 }
 
 static void code_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
@@ -1883,8 +1916,8 @@ static void code_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
 #if !defined(CONFIG_USER_ONLY)
     tb_invalidate_phys_page_fast(phys_addr, 2);
 #endif
-    stw_raw((uint8_t *)addr, val);
-    phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
+    stw_p((uint8_t *)(long)addr, val);
+    phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 0xff;
 }
 
 static void code_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
@@ -1895,8 +1928,8 @@ static void code_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
 #if !defined(CONFIG_USER_ONLY)
     tb_invalidate_phys_page_fast(phys_addr, 4);
 #endif
-    stl_raw((uint8_t *)addr, val);
-    phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
+    stl_p((uint8_t *)(long)addr, val);
+    phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 0xff;
 }
 
 static CPUReadMemoryFunc *code_mem_read[3] = {
@@ -1913,19 +1946,19 @@ static CPUWriteMemoryFunc *code_mem_write[3] = {
 
 static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
-    stb_raw((uint8_t *)addr, val);
+    stb_p((uint8_t *)(long)addr, val);
     tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
 }
 
 static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
-    stw_raw((uint8_t *)addr, val);
+    stw_p((uint8_t *)(long)addr, val);
     tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
 }
 
 static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
-    stl_raw((uint8_t *)addr, val);
+    stl_p((uint8_t *)(long)addr, val);
     tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
 }
 
@@ -1944,7 +1977,7 @@ static void io_mem_init(void)
     io_mem_nb = 5;
 
     /* alloc dirty bits array */
-    phys_ram_dirty = qemu_malloc(phys_ram_size >> TARGET_PAGE_BITS);
+    phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
 }
 
 /* mem_read and mem_write are arrays of functions containing the
@@ -1977,6 +2010,16 @@ int cpu_register_io_memory(int io_index,
     return io_index << IO_MEM_SHIFT;
 }
 
+CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
+{
+    return io_mem_write[io_index >> IO_MEM_SHIFT];
+}
+
+CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
+{
+    return io_mem_read[io_index >> IO_MEM_SHIFT];
+}
+
 /* physical memory access (slow version, mainly for debug) */
 #if defined(CONFIG_USER_ONLY)
 void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, 
@@ -2007,6 +2050,21 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
         addr += l;
     }
 }
+
+/* never used */
+uint32_t ldl_phys(target_phys_addr_t addr)
+{
+    return 0;
+}
+
+void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
+{
+}
+
+void stl_phys(target_phys_addr_t addr, uint32_t val)
+{
+}
+
 #else
 void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, 
                             int len, int is_write)
@@ -2035,17 +2093,17 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
                 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
                 if (l >= 4 && ((addr & 3) == 0)) {
                     /* 32 bit read access */
-                    val = ldl_raw(buf);
+                    val = ldl_p(buf);
                     io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
                     l = 4;
                 } else if (l >= 2 && ((addr & 1) == 0)) {
                     /* 16 bit read access */
-                    val = lduw_raw(buf);
+                    val = lduw_p(buf);
                     io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
                     l = 2;
                 } else {
                     /* 8 bit access */
-                    val = ldub_raw(buf);
+                    val = ldub_p(buf);
                     io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
                     l = 1;
                 }
@@ -2058,7 +2116,7 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
                 /* invalidate code */
                 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
                 /* set dirty bit */
-                phys_ram_dirty[page >> TARGET_PAGE_BITS] = 1;                
+                phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 0xff;
             }
         } else {
             if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
@@ -2068,17 +2126,17 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
                 if (l >= 4 && ((addr & 3) == 0)) {
                     /* 32 bit read access */
                     val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
-                    stl_raw(buf, val);
+                    stl_p(buf, val);
                     l = 4;
                 } else if (l >= 2 && ((addr & 1) == 0)) {
                     /* 16 bit read access */
                     val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
-                    stw_raw(buf, val);
+                    stw_p(buf, val);
                     l = 2;
                 } else {
                     /* 8 bit access */
                     val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
-                    stb_raw(buf, val);
+                    stb_p(buf, val);
                     l = 1;
                 }
             } else {
@@ -2093,6 +2151,96 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
         addr += l;
     }
 }
+
+/* warning: addr must be aligned */
+uint32_t ldl_phys(target_phys_addr_t addr)
+{
+    int io_index;
+    uint8_t *ptr;
+    uint32_t val;
+    unsigned long pd;
+    PhysPageDesc *p;
+
+    p = phys_page_find(addr >> TARGET_PAGE_BITS);
+    if (!p) {
+        pd = IO_MEM_UNASSIGNED;
+    } else {
+        pd = p->phys_offset;
+    }
+        
+    if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
+        (pd & ~TARGET_PAGE_MASK) != IO_MEM_CODE) {
+        /* I/O case */
+        io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+        val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
+    } else {
+        /* RAM case */
+        ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + 
+            (addr & ~TARGET_PAGE_MASK);
+        val = ldl_p(ptr);
+    }
+    return val;
+}
+
+/* warning: addr must be aligned. The ram page is not masked as dirty
+   and the code inside is not invalidated. It is useful if the dirty
+   bits are used to track modified PTEs */
+void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
+{
+    int io_index;
+    uint8_t *ptr;
+    unsigned long pd;
+    PhysPageDesc *p;
+
+    p = phys_page_find(addr >> TARGET_PAGE_BITS);
+    if (!p) {
+        pd = IO_MEM_UNASSIGNED;
+    } else {
+        pd = p->phys_offset;
+    }
+        
+    if ((pd & ~TARGET_PAGE_MASK) != 0) {
+        io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+        io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
+    } else {
+        ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + 
+            (addr & ~TARGET_PAGE_MASK);
+        stl_p(ptr, val);
+    }
+}
+
+/* warning: addr must be aligned */
+/* XXX: optimize code invalidation test */
+void stl_phys(target_phys_addr_t addr, uint32_t val)
+{
+    int io_index;
+    uint8_t *ptr;
+    unsigned long pd;
+    PhysPageDesc *p;
+
+    p = phys_page_find(addr >> TARGET_PAGE_BITS);
+    if (!p) {
+        pd = IO_MEM_UNASSIGNED;
+    } else {
+        pd = p->phys_offset;
+    }
+        
+    if ((pd & ~TARGET_PAGE_MASK) != 0) {
+        io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+        io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
+    } else {
+        unsigned long addr1;
+        addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
+        /* RAM case */
+        ptr = phys_ram_base + addr1;
+        stl_p(ptr, val);
+        /* invalidate code */
+        tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
+        /* set dirty bit */
+        phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 0xff;
+    }
+}
+
 #endif
 
 /* virtual memory access for debug */
@@ -2120,6 +2268,53 @@ int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
     return 0;
 }
 
+void dump_exec_info(FILE *f,
+                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+{
+    int i, target_code_size, max_target_code_size;
+    int direct_jmp_count, direct_jmp2_count, cross_page;
+    TranslationBlock *tb;
+    
+    target_code_size = 0;
+    max_target_code_size = 0;
+    cross_page = 0;
+    direct_jmp_count = 0;
+    direct_jmp2_count = 0;
+    for(i = 0; i < nb_tbs; i++) {
+        tb = &tbs[i];
+        target_code_size += tb->size;
+        if (tb->size > max_target_code_size)
+            max_target_code_size = tb->size;
+        if (tb->page_addr[1] != -1)
+            cross_page++;
+        if (tb->tb_next_offset[0] != 0xffff) {
+            direct_jmp_count++;
+            if (tb->tb_next_offset[1] != 0xffff) {
+                direct_jmp2_count++;
+            }
+        }
+    }
+    /* XXX: avoid using doubles ? */
+    cpu_fprintf(f, "TB count            %d\n", nb_tbs);
+    cpu_fprintf(f, "TB avg target size  %d max=%d bytes\n", 
+                nb_tbs ? target_code_size / nb_tbs : 0,
+                max_target_code_size);
+    cpu_fprintf(f, "TB avg host size    %d bytes (expansion ratio: %0.1f)\n", 
+                nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
+                target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
+    cpu_fprintf(f, "cross page TB count %d (%d%%)\n", 
+            cross_page, 
+            nb_tbs ? (cross_page * 100) / nb_tbs : 0);
+    cpu_fprintf(f, "direct jump count   %d (%d%%) (2 jumps=%d %d%%)\n",
+                direct_jmp_count, 
+                nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
+                direct_jmp2_count,
+                nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
+    cpu_fprintf(f, "TB flush count      %d\n", tb_flush_count);
+    cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
+    cpu_fprintf(f, "TLB flush count     %d\n", tlb_flush_count);
+}
+
 #if !defined(CONFIG_USER_ONLY) 
 
 #define MMUSUFFIX _cmmu