Commit db7b5426a4b424249b4aba3496bf14da69a6625b

Authored by blueswir1
1 parent 57074f98

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
Showing 2 changed files with 225 additions and 7 deletions
cpu-all.h
... ... @@ -858,6 +858,7 @@ extern uint8_t *phys_ram_dirty;
858 858 exception, the write memory callback gets the ram offset instead of
859 859 the physical address */
860 860 #define IO_MEM_ROMD (1)
  861 +#define IO_MEM_SUBPAGE (2)
861 862  
862 863 typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value);
863 864 typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr);
... ...
... ... @@ -48,6 +48,7 @@
48 48 //#define DEBUG_TLB_CHECK
49 49  
50 50 //#define DEBUG_IOPORT
  51 +//#define DEBUG_SUBPAGE
51 52  
52 53 #if !defined(CONFIG_USER_ONLY)
53 54 /* TB consistency checks only implemented for usermode emulation. */
... ... @@ -157,6 +158,14 @@ static int tlb_flush_count;
157 158 static int tb_flush_count;
158 159 static int tb_phys_invalidate_count;
159 160  
  161 +#define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
  162 +typedef struct subpage_t {
  163 + target_phys_addr_t base;
  164 + CPUReadMemoryFunc **mem_read[TARGET_PAGE_SIZE];
  165 + CPUWriteMemoryFunc **mem_write[TARGET_PAGE_SIZE];
  166 + void *opaque[TARGET_PAGE_SIZE];
  167 +} subpage_t;
  168 +
160 169 static void page_init(void)
161 170 {
162 171 /* NOTE: we can always suppose that qemu_host_page_size >=
... ... @@ -1898,6 +1907,30 @@ static inline void tlb_set_dirty(CPUState *env,
1898 1907 }
1899 1908 #endif /* defined(CONFIG_USER_ONLY) */
1900 1909  
  1910 +static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
  1911 + int memory);
  1912 +static void *subpage_init (target_phys_addr_t base, uint32_t *phys,
  1913 + int orig_memory);
  1914 +#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
  1915 + need_subpage) \
  1916 + do { \
  1917 + if (addr > start_addr) \
  1918 + start_addr2 = 0; \
  1919 + else { \
  1920 + start_addr2 = start_addr & ~TARGET_PAGE_MASK; \
  1921 + if (start_addr2 > 0) \
  1922 + need_subpage = 1; \
  1923 + } \
  1924 + \
  1925 + if (end_addr - addr > TARGET_PAGE_SIZE) \
  1926 + end_addr2 = TARGET_PAGE_SIZE - 1; \
  1927 + else { \
  1928 + end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \
  1929 + if (end_addr2 < TARGET_PAGE_SIZE - 1) \
  1930 + need_subpage = 1; \
  1931 + } \
  1932 + } while (0)
  1933 +
1901 1934 /* register physical memory. 'size' must be a multiple of the target
1902 1935 page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
1903 1936 io memory page */
... ... @@ -1908,15 +1941,56 @@ void cpu_register_physical_memory(target_phys_addr_t start_addr,
1908 1941 target_phys_addr_t addr, end_addr;
1909 1942 PhysPageDesc *p;
1910 1943 CPUState *env;
  1944 + unsigned long orig_size = size;
  1945 + void *subpage;
1911 1946  
  1947 + end_addr = start_addr + (target_phys_addr_t)size;
1912 1948 size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
1913   - end_addr = start_addr + size;
1914   - for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
1915   - p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
1916   - p->phys_offset = phys_offset;
1917   - if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
1918   - (phys_offset & IO_MEM_ROMD))
1919   - phys_offset += TARGET_PAGE_SIZE;
  1949 + for(addr = start_addr; addr < end_addr; addr += TARGET_PAGE_SIZE) {
  1950 + p = phys_page_find(addr >> TARGET_PAGE_BITS);
  1951 + if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
  1952 + unsigned long orig_memory = p->phys_offset;
  1953 + target_phys_addr_t start_addr2, end_addr2;
  1954 + int need_subpage = 0;
  1955 +
  1956 + CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
  1957 + need_subpage);
  1958 + if (need_subpage) {
  1959 + if (!(orig_memory & IO_MEM_SUBPAGE)) {
  1960 + subpage = subpage_init((addr & TARGET_PAGE_MASK),
  1961 + &p->phys_offset, orig_memory);
  1962 + } else {
  1963 + subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
  1964 + >> IO_MEM_SHIFT];
  1965 + }
  1966 + subpage_register(subpage, start_addr2, end_addr2, phys_offset);
  1967 + } else {
  1968 + p->phys_offset = phys_offset;
  1969 + if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
  1970 + (phys_offset & IO_MEM_ROMD))
  1971 + phys_offset += TARGET_PAGE_SIZE;
  1972 + }
  1973 + } else {
  1974 + p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
  1975 + p->phys_offset = phys_offset;
  1976 + if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
  1977 + (phys_offset & IO_MEM_ROMD))
  1978 + phys_offset += TARGET_PAGE_SIZE;
  1979 + else {
  1980 + target_phys_addr_t start_addr2, end_addr2;
  1981 + int need_subpage = 0;
  1982 +
  1983 + CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
  1984 + end_addr2, need_subpage);
  1985 +
  1986 + if (need_subpage) {
  1987 + subpage = subpage_init((addr & TARGET_PAGE_MASK),
  1988 + &p->phys_offset, IO_MEM_UNASSIGNED);
  1989 + subpage_register(subpage, start_addr2, end_addr2,
  1990 + phys_offset);
  1991 + }
  1992 + }
  1993 + }
1920 1994 }
1921 1995  
1922 1996 /* since each CPU stores ram addresses in its TLB cache, we must
... ... @@ -2158,6 +2232,149 @@ static CPUWriteMemoryFunc *watch_mem_write[3] = {
2158 2232 };
2159 2233 #endif
2160 2234  
  2235 +static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr,
  2236 + unsigned int len)
  2237 +{
  2238 + CPUReadMemoryFunc **mem_read;
  2239 + uint32_t ret;
  2240 + unsigned int idx;
  2241 +
  2242 + idx = SUBPAGE_IDX(addr - mmio->base);
  2243 +#if defined(DEBUG_SUBPAGE)
  2244 + printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
  2245 + mmio, len, addr, idx);
  2246 +#endif
  2247 + mem_read = mmio->mem_read[idx];
  2248 + ret = (*mem_read[len])(mmio->opaque[idx], addr);
  2249 +
  2250 + return ret;
  2251 +}
  2252 +
  2253 +static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr,
  2254 + uint32_t value, unsigned int len)
  2255 +{
  2256 + CPUWriteMemoryFunc **mem_write;
  2257 + unsigned int idx;
  2258 +
  2259 + idx = SUBPAGE_IDX(addr - mmio->base);
  2260 +#if defined(DEBUG_SUBPAGE)
  2261 + printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
  2262 + mmio, len, addr, idx, value);
  2263 +#endif
  2264 + mem_write = mmio->mem_write[idx];
  2265 + (*mem_write[len])(mmio->opaque[idx], addr, value);
  2266 +}
  2267 +
  2268 +static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr)
  2269 +{
  2270 +#if defined(DEBUG_SUBPAGE)
  2271 + printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
  2272 +#endif
  2273 +
  2274 + return subpage_readlen(opaque, addr, 0);
  2275 +}
  2276 +
  2277 +static void subpage_writeb (void *opaque, target_phys_addr_t addr,
  2278 + uint32_t value)
  2279 +{
  2280 +#if defined(DEBUG_SUBPAGE)
  2281 + printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
  2282 +#endif
  2283 + subpage_writelen(opaque, addr, value, 0);
  2284 +}
  2285 +
  2286 +static uint32_t subpage_readw (void *opaque, target_phys_addr_t addr)
  2287 +{
  2288 +#if defined(DEBUG_SUBPAGE)
  2289 + printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
  2290 +#endif
  2291 +
  2292 + return subpage_readlen(opaque, addr, 1);
  2293 +}
  2294 +
  2295 +static void subpage_writew (void *opaque, target_phys_addr_t addr,
  2296 + uint32_t value)
  2297 +{
  2298 +#if defined(DEBUG_SUBPAGE)
  2299 + printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
  2300 +#endif
  2301 + subpage_writelen(opaque, addr, value, 1);
  2302 +}
  2303 +
  2304 +static uint32_t subpage_readl (void *opaque, target_phys_addr_t addr)
  2305 +{
  2306 +#if defined(DEBUG_SUBPAGE)
  2307 + printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
  2308 +#endif
  2309 +
  2310 + return subpage_readlen(opaque, addr, 2);
  2311 +}
  2312 +
  2313 +static void subpage_writel (void *opaque,
  2314 + target_phys_addr_t addr, uint32_t value)
  2315 +{
  2316 +#if defined(DEBUG_SUBPAGE)
  2317 + printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
  2318 +#endif
  2319 + subpage_writelen(opaque, addr, value, 2);
  2320 +}
  2321 +
  2322 +static CPUReadMemoryFunc *subpage_read[] = {
  2323 + &subpage_readb,
  2324 + &subpage_readw,
  2325 + &subpage_readl,
  2326 +};
  2327 +
  2328 +static CPUWriteMemoryFunc *subpage_write[] = {
  2329 + &subpage_writeb,
  2330 + &subpage_writew,
  2331 + &subpage_writel,
  2332 +};
  2333 +
  2334 +static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
  2335 + int memory)
  2336 +{
  2337 + int idx, eidx;
  2338 +
  2339 + if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
  2340 + return -1;
  2341 + idx = SUBPAGE_IDX(start);
  2342 + eidx = SUBPAGE_IDX(end);
  2343 +#if defined(DEBUG_SUBPAGE)
  2344 + printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %d\n", __func__,
  2345 + mmio, start, end, idx, eidx, memory);
  2346 +#endif
  2347 + memory >>= IO_MEM_SHIFT;
  2348 + for (; idx <= eidx; idx++) {
  2349 + mmio->mem_read[idx] = io_mem_read[memory];
  2350 + mmio->mem_write[idx] = io_mem_write[memory];
  2351 + mmio->opaque[idx] = io_mem_opaque[memory];
  2352 + }
  2353 +
  2354 + return 0;
  2355 +}
  2356 +
  2357 +static void *subpage_init (target_phys_addr_t base, uint32_t *phys,
  2358 + int orig_memory)
  2359 +{
  2360 + subpage_t *mmio;
  2361 + int subpage_memory;
  2362 +
  2363 + mmio = qemu_mallocz(sizeof(subpage_t));
  2364 + if (mmio != NULL) {
  2365 + mmio->base = base;
  2366 + subpage_memory = cpu_register_io_memory(0, subpage_read, subpage_write, mmio);
  2367 +#if defined(DEBUG_SUBPAGE)
  2368 + printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
  2369 + mmio, base, TARGET_PAGE_SIZE, subpage_memory);
  2370 +#endif
  2371 + *phys = subpage_memory | IO_MEM_SUBPAGE;
  2372 + subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory);
  2373 + }
  2374 +
  2375 + return mmio;
  2376 +}
  2377 +
2161 2378 static void io_mem_init(void)
2162 2379 {
2163 2380 cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
... ...