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.
This commit is contained in:
parent
f4b7a16f7b
commit
9843d7a625
@ -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_seg[NR_DEVS]; /* segment index of each device */
|
||||||
PRIVATE int m_device; /* current device */
|
PRIVATE int m_device; /* current device */
|
||||||
PRIVATE struct kinfo kinfo; /* kernel information */
|
PRIVATE struct kinfo kinfo; /* kernel information */
|
||||||
PRIVATE struct machine machine; /* machine information */
|
|
||||||
|
|
||||||
extern int errno; /* error number for PM calls */
|
extern int errno; /* error number for PM calls */
|
||||||
|
|
||||||
@ -69,6 +68,12 @@ PRIVATE struct driver m_dtab = {
|
|||||||
NULL
|
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. */
|
/* Buffer for the /dev/zero null byte feed. */
|
||||||
#define ZERO_BUF_SIZE 1024
|
#define ZERO_BUF_SIZE 1024
|
||||||
PRIVATE char dev_zero[ZERO_BUF_SIZE];
|
PRIVATE char dev_zero[ZERO_BUF_SIZE];
|
||||||
@ -133,14 +138,11 @@ int safe; /* safe copies */
|
|||||||
int seg;
|
int seg;
|
||||||
unsigned count, left, chunk;
|
unsigned count, left, chunk;
|
||||||
vir_bytes user_vir, vir_offset = 0;
|
vir_bytes user_vir, vir_offset = 0;
|
||||||
phys_bytes user_phys;
|
|
||||||
struct device *dv;
|
struct device *dv;
|
||||||
unsigned long dv_size;
|
unsigned long dv_size;
|
||||||
int s, r;
|
int s, r;
|
||||||
off_t position;
|
off_t position;
|
||||||
|
|
||||||
static int n = 0;
|
|
||||||
|
|
||||||
if(!safe) {
|
if(!safe) {
|
||||||
printf("m_transfer: unsafe?\n");
|
printf("m_transfer: unsafe?\n");
|
||||||
return EPERM;
|
return EPERM;
|
||||||
@ -187,32 +189,56 @@ int safe; /* safe copies */
|
|||||||
}
|
}
|
||||||
break;
|
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:
|
case MEM_DEV:
|
||||||
if (position >= dv_size) {
|
{
|
||||||
printf("memory: read 0x%lx beyond physical memory of 0x%lx\n",
|
u32_t pagestart, page_off;
|
||||||
position, dv_size);
|
static u32_t pagestart_mapped;
|
||||||
|
static int any_mapped = 0;
|
||||||
|
int r;
|
||||||
|
u32_t subcount;
|
||||||
|
|
||||||
|
if (position >= dv_size)
|
||||||
return(OK); /* check for EOF */
|
return(OK); /* check for EOF */
|
||||||
}
|
if (position + count > dv_size)
|
||||||
if (position + count > dv_size) {
|
|
||||||
printf("memory: truncating count from %d to ", count);
|
|
||||||
count = dv_size - position;
|
count = dv_size - position;
|
||||||
printf("%d (size %d)\n", count, dv_size);
|
|
||||||
}
|
|
||||||
mem_phys = cv64ul(dv->dv_base) + position;
|
mem_phys = cv64ul(dv->dv_base) + position;
|
||||||
if((r=sys_umap(proc_nr, GRANT_SEG, user_vir,
|
|
||||||
count + vir_offset, &user_phys)) != OK) {
|
page_off = mem_phys % PAGE_SIZE;
|
||||||
panic("MEM","sys_umap failed in m_transfer",r);
|
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 */
|
if (opcode == DEV_GATHER_S) { /* copy data */
|
||||||
sys_physcopy(NONE, PHYS_SEG, mem_phys,
|
s=sys_safecopyto(proc_nr, user_vir,
|
||||||
NONE, PHYS_SEG, user_phys + vir_offset, count);
|
vir_offset, pagedata_aligned+page_off, subcount, D);
|
||||||
} else {
|
} else {
|
||||||
sys_physcopy(NONE, PHYS_SEG, user_phys + vir_offset,
|
s=sys_safecopyfrom(proc_nr, user_vir,
|
||||||
NONE, PHYS_SEG, mem_phys, count);
|
vir_offset, pagedata_aligned+page_off, subcount, D);
|
||||||
}
|
}
|
||||||
|
if(s != OK)
|
||||||
|
return s;
|
||||||
|
count = subcount;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Null byte stream generator. */
|
/* Null byte stream generator. */
|
||||||
case ZERO_DEV:
|
case ZERO_DEV:
|
||||||
@ -224,7 +250,7 @@ int safe; /* safe copies */
|
|||||||
s=sys_safecopyto(proc_nr, user_vir,
|
s=sys_safecopyto(proc_nr, user_vir,
|
||||||
vir_offset+suboffset, (vir_bytes) dev_zero, chunk, D);
|
vir_offset+suboffset, (vir_bytes) dev_zero, chunk, D);
|
||||||
if(s != OK)
|
if(s != OK)
|
||||||
report("MEM","sys_vircopy failed", s);
|
report("MEM","sys_safecopyto failed", s);
|
||||||
left -= chunk;
|
left -= chunk;
|
||||||
suboffset += chunk;
|
suboffset += chunk;
|
||||||
}
|
}
|
||||||
@ -290,30 +316,12 @@ PRIVATE void m_init()
|
|||||||
/* Initialize this task. All minor devices are initialized one by one. */
|
/* Initialize this task. All minor devices are initialized one by one. */
|
||||||
u32_t ramdev_size;
|
u32_t ramdev_size;
|
||||||
u32_t ramdev_base;
|
u32_t ramdev_base;
|
||||||
message m;
|
|
||||||
int i, s;
|
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))) {
|
if (OK != (s=sys_getkinfo(&kinfo))) {
|
||||||
panic("MEM","Couldn't get kernel information.",s);
|
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. */
|
/* Install remote segment for /dev/kmem memory. */
|
||||||
m_geom[KMEM_DEV].dv_base = cvul64(kinfo.kmem_base);
|
m_geom[KMEM_DEV].dv_base = cvul64(kinfo.kmem_base);
|
||||||
m_geom[KMEM_DEV].dv_size = cvul64(kinfo.kmem_size);
|
m_geom[KMEM_DEV].dv_size = cvul64(kinfo.kmem_size);
|
||||||
@ -355,8 +363,12 @@ PRIVATE void m_init()
|
|||||||
dev_zero[i] = '\0';
|
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. */
|
/* 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;
|
u32_t ramdev_size;
|
||||||
phys_bytes ramdev_base;
|
phys_bytes ramdev_base;
|
||||||
message m;
|
|
||||||
int s;
|
int s;
|
||||||
|
|
||||||
/* A ramdisk can be created only once, and only on RAM disk device. */
|
/* A ramdisk can be created only once, and only on RAM disk device. */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user