Implement generic sub-page I/O based on earlier work by J. Mayer.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2868 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
		
							parent
							
								
									57074f98bb
								
							
						
					
					
						commit
						db7b5426a4
					
				| @ -858,6 +858,7 @@ extern uint8_t *phys_ram_dirty; | ||||
|    exception, the write memory callback gets the ram offset instead of | ||||
|    the physical address */ | ||||
| #define IO_MEM_ROMD        (1) | ||||
| #define IO_MEM_SUBPAGE     (2) | ||||
| 
 | ||||
| typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value); | ||||
| typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr); | ||||
|  | ||||
							
								
								
									
										231
									
								
								exec.c
									
									
									
									
									
								
							
							
						
						
									
										231
									
								
								exec.c
									
									
									
									
									
								
							| @ -48,6 +48,7 @@ | ||||
| //#define DEBUG_TLB_CHECK 
 | ||||
| 
 | ||||
| //#define DEBUG_IOPORT
 | ||||
| //#define DEBUG_SUBPAGE
 | ||||
| 
 | ||||
| #if !defined(CONFIG_USER_ONLY) | ||||
| /* TB consistency checks only implemented for usermode emulation.  */ | ||||
| @ -157,6 +158,14 @@ static int tlb_flush_count; | ||||
| static int tb_flush_count; | ||||
| static int tb_phys_invalidate_count; | ||||
| 
 | ||||
| #define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK) | ||||
| typedef struct subpage_t { | ||||
|     target_phys_addr_t base; | ||||
|     CPUReadMemoryFunc **mem_read[TARGET_PAGE_SIZE]; | ||||
|     CPUWriteMemoryFunc **mem_write[TARGET_PAGE_SIZE]; | ||||
|     void *opaque[TARGET_PAGE_SIZE]; | ||||
| } subpage_t; | ||||
| 
 | ||||
| static void page_init(void) | ||||
| { | ||||
|     /* NOTE: we can always suppose that qemu_host_page_size >=
 | ||||
| @ -1898,6 +1907,30 @@ static inline void tlb_set_dirty(CPUState *env, | ||||
| } | ||||
| #endif /* defined(CONFIG_USER_ONLY) */ | ||||
| 
 | ||||
| static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end, | ||||
|                              int memory); | ||||
| static void *subpage_init (target_phys_addr_t base, uint32_t *phys, | ||||
|                            int orig_memory); | ||||
| #define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \ | ||||
|                       need_subpage)                                     \ | ||||
|     do {                                                                \ | ||||
|         if (addr > start_addr)                                          \ | ||||
|             start_addr2 = 0;                                            \ | ||||
|         else {                                                          \ | ||||
|             start_addr2 = start_addr & ~TARGET_PAGE_MASK;               \ | ||||
|             if (start_addr2 > 0)                                        \ | ||||
|                 need_subpage = 1;                                       \ | ||||
|         }                                                               \ | ||||
|                                                                         \ | ||||
|         if (end_addr - addr > TARGET_PAGE_SIZE)                         \ | ||||
|             end_addr2 = TARGET_PAGE_SIZE - 1;                           \ | ||||
|         else {                                                          \ | ||||
|             end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \ | ||||
|             if (end_addr2 < TARGET_PAGE_SIZE - 1)                       \ | ||||
|                 need_subpage = 1;                                       \ | ||||
|         }                                                               \ | ||||
|     } while (0) | ||||
| 
 | ||||
| /* register physical memory. 'size' must be a multiple of the target
 | ||||
|    page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an | ||||
|    io memory page */ | ||||
| @ -1908,15 +1941,56 @@ void cpu_register_physical_memory(target_phys_addr_t start_addr, | ||||
|     target_phys_addr_t addr, end_addr; | ||||
|     PhysPageDesc *p; | ||||
|     CPUState *env; | ||||
|     unsigned long orig_size = size; | ||||
|     void *subpage; | ||||
| 
 | ||||
|     end_addr = start_addr + (target_phys_addr_t)size; | ||||
|     size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK; | ||||
|     end_addr = start_addr + size; | ||||
|     for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) { | ||||
|         p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1); | ||||
|         p->phys_offset = phys_offset; | ||||
|         if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM || | ||||
|             (phys_offset & IO_MEM_ROMD)) | ||||
|             phys_offset += TARGET_PAGE_SIZE; | ||||
|     for(addr = start_addr; addr < end_addr; addr += TARGET_PAGE_SIZE) { | ||||
|         p = phys_page_find(addr >> TARGET_PAGE_BITS); | ||||
|         if (p && p->phys_offset != IO_MEM_UNASSIGNED) { | ||||
|             unsigned long orig_memory = p->phys_offset; | ||||
|             target_phys_addr_t start_addr2, end_addr2; | ||||
|             int need_subpage = 0; | ||||
| 
 | ||||
|             CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, | ||||
|                           need_subpage); | ||||
|             if (need_subpage) { | ||||
|                 if (!(orig_memory & IO_MEM_SUBPAGE)) { | ||||
|                     subpage = subpage_init((addr & TARGET_PAGE_MASK), | ||||
|                                            &p->phys_offset, orig_memory); | ||||
|                 } else { | ||||
|                     subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK) | ||||
|                                             >> IO_MEM_SHIFT]; | ||||
|                 } | ||||
|                 subpage_register(subpage, start_addr2, end_addr2, phys_offset); | ||||
|             } else { | ||||
|                 p->phys_offset = phys_offset; | ||||
|                 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM || | ||||
|                     (phys_offset & IO_MEM_ROMD)) | ||||
|                     phys_offset += TARGET_PAGE_SIZE; | ||||
|             } | ||||
|         } else { | ||||
|             p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1); | ||||
|             p->phys_offset = phys_offset; | ||||
|             if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM || | ||||
|                 (phys_offset & IO_MEM_ROMD)) | ||||
|                 phys_offset += TARGET_PAGE_SIZE; | ||||
|             else { | ||||
|                 target_phys_addr_t start_addr2, end_addr2; | ||||
|                 int need_subpage = 0; | ||||
| 
 | ||||
|                 CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, | ||||
|                               end_addr2, need_subpage); | ||||
| 
 | ||||
|                 if (need_subpage) { | ||||
|                     subpage = subpage_init((addr & TARGET_PAGE_MASK), | ||||
|                                            &p->phys_offset, IO_MEM_UNASSIGNED); | ||||
|                     subpage_register(subpage, start_addr2, end_addr2, | ||||
|                                      phys_offset); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     /* since each CPU stores ram addresses in its TLB cache, we must
 | ||||
| @ -2158,6 +2232,149 @@ static CPUWriteMemoryFunc *watch_mem_write[3] = { | ||||
| }; | ||||
| #endif | ||||
| 
 | ||||
| static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr, | ||||
|                                  unsigned int len) | ||||
| { | ||||
|     CPUReadMemoryFunc **mem_read; | ||||
|     uint32_t ret; | ||||
|     unsigned int idx; | ||||
| 
 | ||||
|     idx = SUBPAGE_IDX(addr - mmio->base); | ||||
| #if defined(DEBUG_SUBPAGE) | ||||
|     printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__, | ||||
|            mmio, len, addr, idx); | ||||
| #endif | ||||
|     mem_read = mmio->mem_read[idx]; | ||||
|     ret = (*mem_read[len])(mmio->opaque[idx], addr); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr, | ||||
|                               uint32_t value, unsigned int len) | ||||
| { | ||||
|     CPUWriteMemoryFunc **mem_write; | ||||
|     unsigned int idx; | ||||
| 
 | ||||
|     idx = SUBPAGE_IDX(addr - mmio->base); | ||||
| #if defined(DEBUG_SUBPAGE) | ||||
|     printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__, | ||||
|            mmio, len, addr, idx, value); | ||||
| #endif | ||||
|     mem_write = mmio->mem_write[idx]; | ||||
|     (*mem_write[len])(mmio->opaque[idx], addr, value); | ||||
| } | ||||
| 
 | ||||
| static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr) | ||||
| { | ||||
| #if defined(DEBUG_SUBPAGE) | ||||
|     printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); | ||||
| #endif | ||||
| 
 | ||||
|     return subpage_readlen(opaque, addr, 0); | ||||
| } | ||||
| 
 | ||||
| static void subpage_writeb (void *opaque, target_phys_addr_t addr, | ||||
|                             uint32_t value) | ||||
| { | ||||
| #if defined(DEBUG_SUBPAGE) | ||||
|     printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value); | ||||
| #endif | ||||
|     subpage_writelen(opaque, addr, value, 0); | ||||
| } | ||||
| 
 | ||||
| static uint32_t subpage_readw (void *opaque, target_phys_addr_t addr) | ||||
| { | ||||
| #if defined(DEBUG_SUBPAGE) | ||||
|     printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); | ||||
| #endif | ||||
| 
 | ||||
|     return subpage_readlen(opaque, addr, 1); | ||||
| } | ||||
| 
 | ||||
| static void subpage_writew (void *opaque, target_phys_addr_t addr, | ||||
|                             uint32_t value) | ||||
| { | ||||
| #if defined(DEBUG_SUBPAGE) | ||||
|     printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value); | ||||
| #endif | ||||
|     subpage_writelen(opaque, addr, value, 1); | ||||
| } | ||||
| 
 | ||||
| static uint32_t subpage_readl (void *opaque, target_phys_addr_t addr) | ||||
| { | ||||
| #if defined(DEBUG_SUBPAGE) | ||||
|     printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); | ||||
| #endif | ||||
| 
 | ||||
|     return subpage_readlen(opaque, addr, 2); | ||||
| } | ||||
| 
 | ||||
| static void subpage_writel (void *opaque, | ||||
|                          target_phys_addr_t addr, uint32_t value) | ||||
| { | ||||
| #if defined(DEBUG_SUBPAGE) | ||||
|     printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value); | ||||
| #endif | ||||
|     subpage_writelen(opaque, addr, value, 2); | ||||
| } | ||||
| 
 | ||||
| static CPUReadMemoryFunc *subpage_read[] = { | ||||
|     &subpage_readb, | ||||
|     &subpage_readw, | ||||
|     &subpage_readl, | ||||
| }; | ||||
| 
 | ||||
| static CPUWriteMemoryFunc *subpage_write[] = { | ||||
|     &subpage_writeb, | ||||
|     &subpage_writew, | ||||
|     &subpage_writel, | ||||
| }; | ||||
| 
 | ||||
| static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end, | ||||
|                              int memory) | ||||
| { | ||||
|     int idx, eidx; | ||||
| 
 | ||||
|     if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE) | ||||
|         return -1; | ||||
|     idx = SUBPAGE_IDX(start); | ||||
|     eidx = SUBPAGE_IDX(end); | ||||
| #if defined(DEBUG_SUBPAGE) | ||||
|     printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %d\n", __func__, | ||||
|            mmio, start, end, idx, eidx, memory); | ||||
| #endif | ||||
|     memory >>= IO_MEM_SHIFT; | ||||
|     for (; idx <= eidx; idx++) { | ||||
|         mmio->mem_read[idx] = io_mem_read[memory]; | ||||
|         mmio->mem_write[idx] = io_mem_write[memory]; | ||||
|         mmio->opaque[idx] = io_mem_opaque[memory]; | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static void *subpage_init (target_phys_addr_t base, uint32_t *phys, | ||||
|                            int orig_memory) | ||||
| { | ||||
|     subpage_t *mmio; | ||||
|     int subpage_memory; | ||||
| 
 | ||||
|     mmio = qemu_mallocz(sizeof(subpage_t)); | ||||
|     if (mmio != NULL) { | ||||
|         mmio->base = base; | ||||
|         subpage_memory = cpu_register_io_memory(0, subpage_read, subpage_write, mmio); | ||||
| #if defined(DEBUG_SUBPAGE) | ||||
|         printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__, | ||||
|                mmio, base, TARGET_PAGE_SIZE, subpage_memory); | ||||
| #endif | ||||
|         *phys = subpage_memory | IO_MEM_SUBPAGE; | ||||
|         subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory); | ||||
|     } | ||||
| 
 | ||||
|     return mmio; | ||||
| } | ||||
| 
 | ||||
| static void io_mem_init(void) | ||||
| { | ||||
|     cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 blueswir1
						blueswir1