From: Ben Gras Date: Fri, 9 Mar 2007 16:03:19 +0000 (+0000) Subject: For /dev/mem, map in memory to be copied to memory's own address space X-Git-Tag: v3.1.3~44 X-Git-Url: http://zhaoyanbai.com/repos/Bv9ARM.ch03.html?a=commitdiff_plain;h=9843d7a625abdf66f0d5f8fb529cdb7dcfd86076;p=minix.git For /dev/mem, map in memory to be copied to memory's own address space one page at a time, and use safecopies to copy it to the requesting process. This lets /dev/mem access the entire physical address space, as the minix page tables only allow access by default to physical RAM, which breaks e.g. the VESA X driver in some cases. --- diff --git a/drivers/memory/memory.c b/drivers/memory/memory.c index 028ed65e0..f6564d697 100644 --- a/drivers/memory/memory.c +++ b/drivers/memory/memory.c @@ -38,7 +38,6 @@ PRIVATE struct device m_geom[NR_DEVS]; /* base and size of each device */ PRIVATE int m_seg[NR_DEVS]; /* segment index of each device */ PRIVATE int m_device; /* current device */ PRIVATE struct kinfo kinfo; /* kernel information */ -PRIVATE struct machine machine; /* machine information */ extern int errno; /* error number for PM calls */ @@ -69,6 +68,12 @@ PRIVATE struct driver m_dtab = { NULL }; +/* One page of temporary mapping area - enough to be able to page-align + * one page. + */ +static char pagedata_buf[2*PAGE_SIZE]; +vir_bytes pagedata_aligned; + /* Buffer for the /dev/zero null byte feed. */ #define ZERO_BUF_SIZE 1024 PRIVATE char dev_zero[ZERO_BUF_SIZE]; @@ -133,14 +138,11 @@ int safe; /* safe copies */ int seg; unsigned count, left, chunk; vir_bytes user_vir, vir_offset = 0; - phys_bytes user_phys; struct device *dv; unsigned long dv_size; int s, r; off_t position; - static int n = 0; - if(!safe) { printf("m_transfer: unsafe?\n"); return EPERM; @@ -187,32 +189,56 @@ int safe; /* safe copies */ } break; - /* Physical copying. Only used to access entire memory. */ + /* Physical copying. Only used to access entire memory. + * Transfer one 'page window' at a time. + */ case MEM_DEV: - if (position >= dv_size) { - printf("memory: read 0x%lx beyond physical memory of 0x%lx\n", - position, dv_size); + { + u32_t pagestart, page_off; + static u32_t pagestart_mapped; + static int any_mapped = 0; + int r; + u32_t subcount; + + if (position >= dv_size) return(OK); /* check for EOF */ - } - if (position + count > dv_size) { - printf("memory: truncating count from %d to ", count); + if (position + count > dv_size) count = dv_size - position; - printf("%d (size %d)\n", count, dv_size); - } mem_phys = cv64ul(dv->dv_base) + position; - if((r=sys_umap(proc_nr, GRANT_SEG, user_vir, - count + vir_offset, &user_phys)) != OK) { - panic("MEM","sys_umap failed in m_transfer",r); - } + + page_off = mem_phys % PAGE_SIZE; + pagestart = mem_phys - page_off; + + /* All memory to the map call has to be page-aligned. + * Don't have to map same page over and over. + */ + if(!any_mapped || pagestart_mapped != pagestart) { + if((r=sys_vm_map(SELF, 1, pagedata_aligned, + PAGE_SIZE, pagestart)) != OK) { + printf("memory: sys_vm_map failed: %d\n", r); + return r; + } + any_mapped = 1; + pagestart_mapped = pagestart; + } + + /* how much to be done within this page. */ + subcount = PAGE_SIZE-page_off; + if(subcount > count) + subcount = count; if (opcode == DEV_GATHER_S) { /* copy data */ - sys_physcopy(NONE, PHYS_SEG, mem_phys, - NONE, PHYS_SEG, user_phys + vir_offset, count); + s=sys_safecopyto(proc_nr, user_vir, + vir_offset, pagedata_aligned+page_off, subcount, D); } else { - sys_physcopy(NONE, PHYS_SEG, user_phys + vir_offset, - NONE, PHYS_SEG, mem_phys, count); + s=sys_safecopyfrom(proc_nr, user_vir, + vir_offset, pagedata_aligned+page_off, subcount, D); } + if(s != OK) + return s; + count = subcount; break; + } /* Null byte stream generator. */ case ZERO_DEV: @@ -224,7 +250,7 @@ int safe; /* safe copies */ s=sys_safecopyto(proc_nr, user_vir, vir_offset+suboffset, (vir_bytes) dev_zero, chunk, D); if(s != OK) - report("MEM","sys_vircopy failed", s); + report("MEM","sys_safecopyto failed", s); left -= chunk; suboffset += chunk; } @@ -290,30 +316,12 @@ PRIVATE void m_init() /* Initialize this task. All minor devices are initialized one by one. */ u32_t ramdev_size; u32_t ramdev_base; - message m; int i, s; - phys_bytes mem_top = 0; - - /* Physical memory, to check validity of /dev/mem access. */ -#define MAX_MEM_RANGES 10 - struct memory mem_chunks[MAX_MEM_RANGES]; if (OK != (s=sys_getkinfo(&kinfo))) { panic("MEM","Couldn't get kernel information.",s); } - /* Obtain physical memory chunks for /dev/mem memory. */ - if(env_memory_parse(mem_chunks, MAX_MEM_RANGES) != OK) - printf("memory driver: no memory layout, /dev/mem won't work\n"); - else { - for(i = 0; i < MAX_MEM_RANGES; i++) { - phys_bytes top; - top = mem_chunks[i].base + mem_chunks[i].size; - if(top > mem_top) - mem_top = top; - } - } - /* Install remote segment for /dev/kmem memory. */ m_geom[KMEM_DEV].dv_base = cvul64(kinfo.kmem_base); m_geom[KMEM_DEV].dv_size = cvul64(kinfo.kmem_size); @@ -355,8 +363,12 @@ PRIVATE void m_init() dev_zero[i] = '\0'; } + /* Page-align page pointer. */ + pagedata_aligned = (u32_t) pagedata_buf + PAGE_SIZE; + pagedata_aligned -= pagedata_aligned % PAGE_SIZE; + /* Set up memory range for /dev/mem. */ - m_geom[MEM_DEV].dv_size = cvul64(mem_top); + m_geom[MEM_DEV].dv_size = cvul64(0xffffffff); } /*===========================================================================* @@ -384,7 +396,6 @@ int safe; u32_t ramdev_size; phys_bytes ramdev_base; - message m; int s; /* A ramdisk can be created only once, and only on RAM disk device. */