/[qemu]/qemu/target-sparc/helper.c
ViewVC logotype

Diff of /qemu/target-sparc/helper.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.4 by bellard, Sat Oct 9 18:08:01 2004 UTC revision 1.5 by bellard, Sun Dec 19 23:18:01 2004 UTC
# Line 19  Line 19 
19   */   */
20  #include "exec.h"  #include "exec.h"
21    
22  #define DEBUG_PCALL  //#define DEBUG_PCALL
23    //#define DEBUG_MMU
24    
25  /* Sparc MMU emulation */  /* Sparc MMU emulation */
26  int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,  int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
# Line 108  static const int rw_table[2][8] = { Line 109  static const int rw_table[2][8] = {
109      { 0, 1, 0, 1, 0, 0, 0, 0 }      { 0, 1, 0, 1, 0, 0, 0, 0 }
110  };  };
111    
112    int get_physical_address (CPUState *env, uint32_t *physical, int *prot,
113  /* Perform address translation */                            int *access_index, uint32_t address, int rw,
114  int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,                            int is_user)
                               int is_user, int is_softmmu)  
115  {  {
116      int exception = 0;      int access_perms = 0;
117      int access_perms = 0, access_index = 0;      target_phys_addr_t pde_ptr;
     uint8_t *pde_ptr;  
118      uint32_t pde, virt_addr;      uint32_t pde, virt_addr;
119      int error_code = 0, is_dirty, prot, ret = 0;      int error_code = 0, is_dirty;
120      unsigned long paddr, vaddr, page_offset;      unsigned long page_offset;
   
     if (env->user_mode_only) {  
         /* user mode only emulation */  
         ret = -2;  
         goto do_fault;  
     }  
121    
122      virt_addr = address & TARGET_PAGE_MASK;      virt_addr = address & TARGET_PAGE_MASK;
123      if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */      if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
124          paddr = address;          *physical = address;
125          page_offset = address & (TARGET_PAGE_SIZE - 1);          *prot = PAGE_READ | PAGE_WRITE;
126          prot = PAGE_READ | PAGE_WRITE;          return 0;
         goto do_mapping;  
127      }      }
128    
129      /* SPARC reference MMU table walk: Context table->L1->L2->PTE */      /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
130      /* Context base + context number */      /* Context base + context number */
131      pde_ptr = phys_ram_base + (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4);      pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4);
132      pde = ldl_raw(pde_ptr);      cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
133        bswap32s(&pde);
134    
135      /* Ctx pde */      /* Ctx pde */
136      switch (pde & PTE_ENTRYTYPE_MASK) {      switch (pde & PTE_ENTRYTYPE_MASK) {
137        default:
138      case 0: /* Invalid */      case 0: /* Invalid */
139          error_code = 1;          return 1;
140          goto do_fault;      case 2: /* L0 PTE, maybe should not happen? */
     case 2: /* PTE, maybe should not happen? */  
141      case 3: /* Reserved */      case 3: /* Reserved */
142          error_code = 4;          return 4;
143          goto do_fault;      case 1: /* L0 PDE */
144      case 1: /* L1 PDE */          pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
145          pde_ptr = phys_ram_base + ((address >> 22) & ~3) + ((pde & ~3) << 4);          cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
146          pde = ldl_raw(pde_ptr);          bswap32s(&pde);
147    
148          switch (pde & PTE_ENTRYTYPE_MASK) {          switch (pde & PTE_ENTRYTYPE_MASK) {
149            default:
150          case 0: /* Invalid */          case 0: /* Invalid */
151              error_code = 1;              return 1;
             goto do_fault;  
152          case 3: /* Reserved */          case 3: /* Reserved */
153              error_code = 4;              return 4;
154              goto do_fault;          case 1: /* L1 PDE */
155          case 1: /* L2 PDE */              pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
156              pde_ptr = phys_ram_base + ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);              cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
157              pde = ldl_raw(pde_ptr);              bswap32s(&pde);
158    
159              switch (pde & PTE_ENTRYTYPE_MASK) {              switch (pde & PTE_ENTRYTYPE_MASK) {
160                default:
161              case 0: /* Invalid */              case 0: /* Invalid */
162                  error_code = 1;                  return 1;
                 goto do_fault;  
163              case 3: /* Reserved */              case 3: /* Reserved */
164                  error_code = 4;                  return 4;
165                  goto do_fault;              case 1: /* L2 PDE */
166              case 1: /* L3 PDE */                  pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
167                  pde_ptr = phys_ram_base + ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);                  cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
168                  pde = ldl_raw(pde_ptr);                  bswap32s(&pde);
169    
170                  switch (pde & PTE_ENTRYTYPE_MASK) {                  switch (pde & PTE_ENTRYTYPE_MASK) {
171                    default:
172                  case 0: /* Invalid */                  case 0: /* Invalid */
173                      error_code = 1;                      return 1;
                     goto do_fault;  
174                  case 1: /* PDE, should not happen */                  case 1: /* PDE, should not happen */
175                  case 3: /* Reserved */                  case 3: /* Reserved */
176                      error_code = 4;                      return 4;
                     goto do_fault;  
177                  case 2: /* L3 PTE */                  case 2: /* L3 PTE */
178                      virt_addr = address & TARGET_PAGE_MASK;                      virt_addr = address & TARGET_PAGE_MASK;
179                      page_offset = (address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1);                      page_offset = (address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1);
# Line 201  int cpu_sparc_handle_mmu_fault (CPUState Line 193  int cpu_sparc_handle_mmu_fault (CPUState
193      /* update page modified and dirty bits */      /* update page modified and dirty bits */
194      is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);      is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
195      if (!(pde & PG_ACCESSED_MASK) || is_dirty) {      if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
196            uint32_t tmppde;
197          pde |= PG_ACCESSED_MASK;          pde |= PG_ACCESSED_MASK;
198          if (is_dirty)          if (is_dirty)
199              pde |= PG_MODIFIED_MASK;              pde |= PG_MODIFIED_MASK;
200          stl_raw(pde_ptr, pde);          tmppde = bswap32(pde);
201            cpu_physical_memory_write(pde_ptr, (uint8_t *)&tmppde, 4);
202      }      }
   
203      /* check access */      /* check access */
204      access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);      *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
205      access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;      access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
206      error_code = access_table[access_index][access_perms];      error_code = access_table[*access_index][access_perms];
207      if (error_code)      if (error_code)
208          goto do_fault;          return error_code;
209    
210      /* the page can be put in the TLB */      /* the page can be put in the TLB */
211      prot = PAGE_READ;      *prot = PAGE_READ;
212      if (pde & PG_MODIFIED_MASK) {      if (pde & PG_MODIFIED_MASK) {
213          /* only set write access if already dirty... otherwise wait          /* only set write access if already dirty... otherwise wait
214             for dirty access */             for dirty access */
215          if (rw_table[is_user][access_perms])          if (rw_table[is_user][access_perms])
216                  prot |= PAGE_WRITE;                  *prot |= PAGE_WRITE;
217      }      }
218    
219      /* Even if large ptes, we map only one 4KB page in the cache to      /* Even if large ptes, we map only one 4KB page in the cache to
220         avoid filling it too fast */         avoid filling it too fast */
221      virt_addr = address & TARGET_PAGE_MASK;      *physical = ((pde & PTE_ADDR_MASK) << 4) + page_offset;
222      paddr = ((pde & PTE_ADDR_MASK) << 4) + page_offset;      return 0;
223    }
224    
225    /* Perform address translation */
226    int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
227                                  int is_user, int is_softmmu)
228    {
229        int exception = 0;
230        uint32_t virt_addr, paddr;
231        unsigned long vaddr;
232        int error_code = 0, prot, ret = 0, access_index;
233    
234   do_mapping:      if (env->user_mode_only) {
235      vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1));          /* user mode only emulation */
236            error_code = -2;
237            goto do_fault_user;
238        }
239    
240      ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);      error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user);
241      return ret;      if (error_code == 0) {
242            virt_addr = address & TARGET_PAGE_MASK;
243            vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1));
244            ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
245            return ret;
246        }
247    
  do_fault:  
248      if (env->mmuregs[3]) /* Fault status register */      if (env->mmuregs[3]) /* Fault status register */
249          env->mmuregs[3] = 1; /* overflow (not read before another fault) */          env->mmuregs[3] = 1; /* overflow (not read before another fault) */
250      env->mmuregs[3] |= (access_index << 5) | (error_code << 2) | 2;      env->mmuregs[3] |= (access_index << 5) | (error_code << 2) | 2;
# Line 242  int cpu_sparc_handle_mmu_fault (CPUState Line 252  int cpu_sparc_handle_mmu_fault (CPUState
252    
253      if (env->mmuregs[0] & MMU_NF || env->psret == 0) // No fault      if (env->mmuregs[0] & MMU_NF || env->psret == 0) // No fault
254          return 0;          return 0;
255     do_fault_user:
256      env->exception_index = exception;      env->exception_index = exception;
257      env->error_code = error_code;      env->error_code = error_code;
258      return error_code;      return error_code;
# Line 289  void do_interrupt(int intno, int is_int, Line 299  void do_interrupt(int intno, int is_int,
299                      count, intno, error_code, is_int,                      count, intno, error_code, is_int,
300                      env->pc,                      env->pc,
301                      env->npc, env->regwptr[6]);                      env->npc, env->regwptr[6]);
302  #if 0  #if 1
303          cpu_dump_state(env, logfile, fprintf, 0);          cpu_dump_state(env, logfile, fprintf, 0);
304          {          {
305              int i;              int i;
306              uint8_t *ptr;              uint8_t *ptr;
307    
308              fprintf(logfile, "       code=");              fprintf(logfile, "       code=");
309              ptr = env->pc;              ptr = (uint8_t *)env->pc;
310              for(i = 0; i < 16; i++) {              for(i = 0; i < 16; i++) {
311                  fprintf(logfile, " %02x", ldub(ptr + i));                  fprintf(logfile, " %02x", ldub(ptr + i));
312              }              }
# Line 305  void do_interrupt(int intno, int is_int, Line 316  void do_interrupt(int intno, int is_int,
316          count++;          count++;
317      }      }
318  #endif  #endif
319    #if !defined(CONFIG_USER_ONLY)
320        if (env->psret == 0) {
321            fprintf(logfile, "Trap while interrupts disabled, Error state!\n");
322            qemu_system_shutdown_request();
323            return;
324        }
325    #endif
326      env->psret = 0;      env->psret = 0;
327      cwp = (env->cwp - 1) & (NWINDOWS - 1);      cwp = (env->cwp - 1) & (NWINDOWS - 1);
328      set_cwp(cwp);      set_cwp(cwp);
329      env->regwptr[9] = env->pc;      env->regwptr[9] = env->pc - 4; // XXX?
330      env->regwptr[10] = env->npc;      env->regwptr[10] = env->pc;
331      env->psrps = env->psrs;      env->psrps = env->psrs;
332      env->psrs = 1;      env->psrs = 1;
333      env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);      env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
# Line 322  void raise_exception_err(int exception_i Line 340  void raise_exception_err(int exception_i
340  {  {
341      raise_exception(exception_index);      raise_exception(exception_index);
342  }  }
343    
344    uint32_t mmu_probe(uint32_t address, int mmulev)
345    {
346        target_phys_addr_t pde_ptr;
347        uint32_t pde;
348    
349        /* Context base + context number */
350        pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4);
351        cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
352        bswap32s(&pde);
353        switch (pde & PTE_ENTRYTYPE_MASK) {
354        default:
355        case 0: /* Invalid */
356        case 2: /* PTE, maybe should not happen? */
357        case 3: /* Reserved */
358            return 0;
359        case 1: /* L1 PDE */
360            if (mmulev == 3)
361                return pde;
362            pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
363            cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
364            bswap32s(&pde);
365    
366            switch (pde & PTE_ENTRYTYPE_MASK) {
367            default:
368            case 0: /* Invalid */
369            case 3: /* Reserved */
370                return 0;
371            case 2: /* L1 PTE */
372                return pde;
373            case 1: /* L2 PDE */
374                if (mmulev == 2)
375                    return pde;
376                pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
377                cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
378                bswap32s(&pde);
379    
380                switch (pde & PTE_ENTRYTYPE_MASK) {
381                default:
382                case 0: /* Invalid */
383                case 3: /* Reserved */
384                    return 0;
385                case 2: /* L2 PTE */
386                    return pde;
387                case 1: /* L3 PDE */
388                    if (mmulev == 1)
389                        return pde;
390                    pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
391                    cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
392                    bswap32s(&pde);
393    
394                    switch (pde & PTE_ENTRYTYPE_MASK) {
395                    default:
396                    case 0: /* Invalid */
397                    case 1: /* PDE, should not happen */
398                    case 3: /* Reserved */
399                        return 0;
400                    case 2: /* L3 PTE */
401                        return pde;
402                    }
403                }
404            }
405        }
406        return 0;
407    }
408    
409    void dump_mmu(void)
410    {
411    #ifdef DEBUG_MMU
412        uint32_t pa, va, va1, va2;
413        int n, m, o;
414        target_phys_addr_t pde_ptr;
415        uint32_t pde;
416    
417        printf("MMU dump:\n");
418        pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4);
419        cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
420        bswap32s(&pde);
421        printf("Root ptr: 0x%08x, ctx: %d\n", env->mmuregs[1] << 4, env->mmuregs[2]);
422        for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
423            pde_ptr = mmu_probe(va, 2);
424            if (pde_ptr) {
425                pa = cpu_get_phys_page_debug(env, va);
426                printf("VA: 0x%08x, PA: 0x%08x PDE: 0x%08x\n", va, pa, pde_ptr);
427                for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
428                    pde_ptr = mmu_probe(va1, 1);
429                    if (pde_ptr) {
430                        pa = cpu_get_phys_page_debug(env, va1);
431                        printf(" VA: 0x%08x, PA: 0x%08x PDE: 0x%08x\n", va1, pa, pde_ptr);
432                        for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
433                            pde_ptr = mmu_probe(va2, 0);
434                            if (pde_ptr) {
435                                pa = cpu_get_phys_page_debug(env, va2);
436                                printf("  VA: 0x%08x, PA: 0x%08x PTE: 0x%08x\n", va2, pa, pde_ptr);
437                            }
438                        }
439                    }
440                }
441            }
442        }
443        printf("MMU dump ends\n");
444    #endif
445    }

Legend:
Removed from v.1.4  
changed lines
  Added in v.1.5

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26