On Wed, 26 Jan 2005, Bryn Reeves wrote:
On Wed, 2005-01-26 at 17:34, Chris Friesen wrote:linux-os wrote:
Does this mean that we can't mmap the screen regen buffer at 0x000b8000 anymore?
How do I look at the real-mode interrupt table starting at offset 0? You know that the return value of mmap is to be checked for MAP_FAILED, not for NULL, don't you?
Can't you still map those physical addresses to other virtual addresses?
I think that's the case. The 0 address as refered to here is only for the user virtual address space.
What 'C' standard do you refer to? Seg-faults on null pointers have nothing to do with the 'C' standard and everything to do with the platform.
I believe the ISO/IEC 9899:1999 C Standard explicitly states that dereferencing a null pointer with the unary * operator results in undefined behavior.
Exactly. Undefined. VAX/UNIX allowed assignment to null pointers. BUT it's now such a commonly held assumption that a null pointer is not valid that things will break if this is changed. Doesn't glibc malloc use mmap for small allocations? From the man page:
Wrong! A returned value of 0 is perfectly correct for mmap() when mapping a fixed address. The attached code shows it working perfectly while returning NULL, that event being put on the terminal.
Any kernel changes that break this code are wrong. There are many 'C' runtime library functions that signal a problem (or should signal a problem) by returning NULL. That is, however, the documented behavior of those procedures. Even malloc() which __should__ show a failure to allocate by returning NULL, doesn't work that way because the allocation never fails (even if you are out of memory) as long as the user address space hasn't been corrupted by the user (overwriting buffers).
The seg-fault you get when you de-reference a pointer to NULL is caused by the kernel. You are attempting to access memory that has not been mapped into your address space. Once that memory gets mmap()ed, you will no longer get a seg-fault. Again, the seg-fault has nothing to do with 'C'. It's an implementation behavior that can be changed with mmap().
[SNIPPED...]
Cheers, Dick Johnson Penguin : Linux version 2.6.10 on an i686 machine (5537.79 BogoMips). Notice : All mail here is now cached for review by Dictator Bush. 98.36% of all statistics are fiction.
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <signal.h> #include <fcntl.h> #include <termios.h> #include <sys/types.h> #include <sys/mman.h> #define xxDEBUG #if !defined(PAGE_SIZE) #define PAGE_SIZE 0x1000 #endif #if !defined(PAGE_MASK) #define PAGE_MASK ~(PAGE_SIZE - 1) #endif #if !defined(MAP_FAILED) #define MAP_FAILED (void *) -1 #endif #define UL unsigned long #define ERRORS \ { fprintf(stderr, errmsg, __LINE__,\ __FILE__, errno, strerror(errno));\ exit(EXIT_FAILURE); } #ifdef DEBUG #define DEB(f) (f) #else #define DEB(f) #endif static const char errmsg[]="Error at line %d, file %s (%d) [%s]\n"; static const char mapfile[]="/dev/mem"; #define PROT (PROT_READ|PROT_WRITE) #define FLAGS (MAP_FIXED|MAP_SHARED) /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/ /* * This writes a 'debug-like' dump out the screen. It always writes * 16 lines of 16 characters. It returns the last address displayed. */ static off_t dump(off_t addr); static off_t dump(off_t addr) { size_t i, j; int fd; caddr_t mem; off_t next; unsigned char c, *buf; next = addr; addr &= PAGE_MASK; if((fd = open(mapfile, O_RDWR)) < 0) ERRORS; if((mem = mmap((caddr_t)addr, PAGE_SIZE * 2, PROT, FLAGS, fd, addr)) == MAP_FAILED) { (void)close(fd); fprintf(stderr, "\tCan't map address %08lX\n", (UL) addr); return (off_t)mem; } printf("mmap returned %p (0x%08x)\n", mem, (size_t) mem); buf = (unsigned char *) next; DEB(fprintf(stderr, "Mapped address = 0x%lx\n", addr)); DEB(fprintf(stderr, "Buffer address = %p\n", buf)); for(i=0; i< 0x10; i++) { fprintf(stdout, "\n%08lX ", (UL) next); next += 0x10; for(j=0; j< 0x10; j++) fprintf(stdout, "%02X ", (unsigned int) *buf++); buf -= 0x10; for(j=0; j<0x10; j++) { c = *buf++; if((c < (unsigned char) ' ') || (c > (unsigned char) 'z')) c = (unsigned char) '.'; fprintf(stdout, "%c", c); } } fprintf(stdout, "\n"); (void)fflush(stdout); (void)close(fd); if(munmap(mem, PAGE_SIZE)< 0) ERRORS; return next; } void usage(char *cp) { fprintf(stderr, "Usage\n%s <start address> [end address]\n", cp); exit(EXIT_FAILURE); } int main(int args, char *argv[]) { off_t addr; off_t end; if(args < 2) usage(argv[0]); end = 0; if(sscanf(argv[1], "%lx", &addr) != 1) usage(argv[0]); if(argv[2] != NULL) (void)sscanf(argv[2], "%lx", &end); do { if((addr = dump(addr)) == 0xffffffff) break; } while (end > addr); return 0; }