/dev/kmem /dev/mem PATCH for kernel 2.1.15

Marcin Dalecki (dalecki@sub994.sub.uni-goettingen.de)
Mon, 16 Dec 1996 13:58:20 +0100 (MET)


Just recently I sendid a patch, which fixed the behaviour of /dev/kmem
but broke /dev/mem. During this weekend I took the time to dig something
deeper into the memory mapping organization. Here is the hopefully correct
patch
for the behaviour of the reading functions. We can't relay on /dev/mem in
/dev/kmem after the kernel has been remapped to 0xC0000000.
Just recently someone created an device with major number 1 and minor
number 0. It was called ram but that's exactly what /dev/mem is supposed
to do: read the physical ram mapping. The virtual address space should be
accessed by /dev/kmem (see man 2 kmem or man 2 mem for confirmance.)

The writing function for /dev/kmem still deservs fixing... But the
ability to write into the kernel space wasn't important at this point for
mee.

Marcin

diff -urN linux-old/drivers/char/mem.c linux/drivers/char/mem.c
--- linux-old/drivers/char/mem.c Sat Dec 14 17:35:51 1996
+++ linux/drivers/char/mem.c Sat Dec 14 19:52:42 1996
@@ -34,18 +34,10 @@
void pcwatchdog_init(void);
#endif

-static long read_ram(struct inode * inode, struct file * file,
- char * buf, unsigned long count)
-{
- return -EIO;
-}
-
-static long write_ram(struct inode * inode, struct file * file,
- const char * buf, unsigned long count)
-{
- return -EIO;
-}
-
+/*
+ * This funcions reads the *physical* memory. The f_pos points directly to the
+ * memory location.
+ */
static long read_mem(struct inode * inode, struct file * file,
char * buf, unsigned long count)
{
@@ -53,8 +45,6 @@
unsigned long end_mem;
int read;

- if (count < 0)
- return -EINVAL;
end_mem = __pa(high_memory);
if (p >= end_mem)
return 0;
@@ -83,8 +73,6 @@
unsigned long end_mem;
int written;

- if (count < 0)
- return -EINVAL;
end_mem = __pa(high_memory);
if (p >= end_mem)
return 0;
@@ -130,19 +118,41 @@
return 0;
}

+/*
+ * This function read's the *virtual* memory as seen by the kernel.
+ */
static long read_kmem(struct inode *inode, struct file *file,
char *buf, unsigned long count)
{
- int read1, read2;
+ unsigned long p = file->f_pos;
+ unsigned long read = 0;
+ long virtr;
+
+ if (p < (unsigned long) high_memory) {
+ unsigned long tmp;
+
+ if (count > (unsigned long) high_memory - p)
+ tmp = (unsigned long) high_memory - p;
+ else
+ tmp = count;
+ read = tmp;
+#if defined(__sparc__) /* we don't have page 0 mapped on sparc.. */
+ while (p < PAGE_SIZE && tmp > 0) {
+ put_user(0,buf);
+ buf++;
+ p++;
+ tmp--;
+ }
+#endif
+ copy_to_user(buf, (char *) p, tmp);
+ buf += tmp;
+ }

- read1 = read_mem(inode, file, buf, count);
- if (read1 < 0)
- return read1;
- read2 = vread(buf + read1, (char *) ((unsigned long) file->f_pos), count - read1);
- if (read2 < 0)
- return read2;
- file->f_pos += read2;
- return read1 + read2;
+ virtr = vread(buf, (char *) (unsigned long) file->f_pos, count - read);
+ if (virtr < 0)
+ return virtr;
+ file->f_pos += virtr + read;
+ return virtr + read;
}

static long read_port(struct inode * inode, struct file * file,
@@ -301,19 +311,6 @@
#define zero_lseek null_lseek
#define write_zero write_null

-static struct file_operations ram_fops = {
- memory_lseek,
- read_ram,
- write_ram,
- NULL, /* ram_readdir */
- NULL, /* ram_select */
- NULL, /* ram_ioctl */
- NULL, /* ram_mmap */
- NULL, /* no special open code */
- NULL, /* no special release code */
- NULL /* fsync */
-};
-
static struct file_operations mem_fops = {
memory_lseek,
read_mem,
@@ -393,9 +390,6 @@
static int memory_open(struct inode * inode, struct file * filp)
{
switch (MINOR(inode->i_rdev)) {
- case 0:
- filp->f_op = &ram_fops;
- break;
case 1:
filp->f_op = &mem_fops;
break;