📄 xpram.c
字号:
} else return 0;#endif}/* * expanded memory operations *//*--------------------------------------------------------------------*//* Copy expanded memory page (4kB) into main memory *//* Arguments *//* page_addr: address of target page *//* xpage_index: index of expandeded memory page *//* Return value *//* 0: if operation succeeds *//* non-0: otherwise *//*--------------------------------------------------------------------*/long xpram_page_in (unsigned long page_addr, unsigned long xpage_index){ int cc=0; unsigned long real_page_addr = __pa(page_addr);#ifndef CONFIG_ARCH_S390X __asm__ __volatile__ ( " lr 1,%1 \n" /* r1 = real_page_addr */ " lr 2,%2 \n" /* r2 = xpage_index */ " .long 0xb22e0012 \n" /* pgin r1,r2 */ /* copy page from expanded memory */ "0: ipm %0 \n" /* save status (cc & program mask */ " srl %0,28 \n" /* cc into least significant bits */ "1: \n" /* we are done */ ".section .fixup,\"ax\"\n" /* start of fix up section */ "2: lhi %0,2 \n" /* return unused condition code 2 */ " bras 1,3f \n" /* safe label 1: in r1 and goto 3 */ " .long 1b \n" /* literal containing label 1 */ "3: l 1,0(1) \n" /* load label 1 address into r1 */ " br 1 \n" /* goto label 1 (across sections) */ ".previous \n" /* back in text section */ ".section __ex_table,\"a\"\n" /* start __extable */ " .align 4 \n" " .long 0b,2b \n" /* failure point 0, fixup code 2 */ ".previous \n" : "=d" (cc) : "d" (real_page_addr), "d" (xpage_index) : "cc", "1", "2" );#else /* CONFIG_ARCH_S390X */ __asm__ __volatile__ ( " lgr 1,%1 \n" /* r1 = real_page_addr */ " lgr 2,%2 \n" /* r2 = xpage_index */ " .long 0xb22e0012 \n" /* pgin r1,r2 */ /* copy page from expanded memory */ "0: ipm %0 \n" /* save status (cc & program mask */ " srl %0,28 \n" /* cc into least significant bits */ "1: \n" /* we are done */ ".section .fixup,\"ax\"\n" /* start of fix up section */ "2: lghi %0,2 \n" /* return unused condition code 2 */ " jg 1b \n" /* goto label 1 above */ ".previous \n" /* back in text section */ ".section __ex_table,\"a\"\n" /* start __extable */ " .align 8 \n" " .quad 0b,2b \n" /* failure point 0, fixup code 2 */ ".previous \n" : "=d" (cc) : "d" (real_page_addr), "d" (xpage_index) : "cc", "1", "2" );#endif /* CONFIG_ARCH_S390X */ switch (cc) { case 0: return 0; case 1: return -EIO; case 2: return -ENXIO; case 3: return -ENXIO; default: return -EIO; /* should not happen */ };}/*--------------------------------------------------------------------*//* Copy a 4kB page of main memory to an expanded memory page *//* Arguments *//* page_addr: address of source page *//* xpage_index: index of expandeded memory page *//* Return value *//* 0: if operation succeeds *//* non-0: otherwise *//*--------------------------------------------------------------------*/long xpram_page_out (unsigned long page_addr, unsigned long xpage_index){ int cc=0; unsigned long real_page_addr = __pa(page_addr);#ifndef CONFIG_ARCH_S390X __asm__ __volatile__ ( " lr 1,%1 \n" /* r1 = mem_page */ " lr 2,%2 \n" /* r2 = rpi */ " .long 0xb22f0012 \n" /* pgout r1,r2 */ /* copy page from expanded memory */ "0: ipm %0 \n" /* save status (cc & program mask */ " srl %0,28 \n" /* cc into least significant bits */ "1: \n" /* we are done */ ".section .fixup,\"ax\"\n" /* start of fix up section */ "2: lhi %0,2 \n" /* return unused condition code 2 */ " bras 1,3f \n" /* safe label 1: in r1 and goto 3 */ " .long 1b \n" /* literal containing label 1 */ "3: l 1,0(1) \n" /* load label 1 address into r1 */ " br 1 \n" /* goto label 1 (across sections) */ ".previous \n" /* back in text section */ ".section __ex_table,\"a\"\n" /* start __extable */ " .align 4 \n" " .long 0b,2b \n" /* failure point 0, fixup code 2 */ ".previous \n" : "=d" (cc) : "d" (real_page_addr), "d" (xpage_index) : "cc", "1", "2" );#else /* CONFIG_ARCH_S390X */ __asm__ __volatile__ ( " lgr 1,%1 \n" /* r1 = mem_page */ " lgr 2,%2 \n" /* r2 = rpi */ " .long 0xb22f0012 \n" /* pgout r1,r2 */ /* copy page from expanded memory */ "0: ipm %0 \n" /* save status (cc & program mask */ " srl %0,28 \n" /* cc into least significant bits */ "1: \n" /* we are done */ ".section .fixup,\"ax\"\n" /* start of fix up section */ "2: lghi %0,2 \n" /* return unused condition code 2 */ " jg 1b \n" /* goto label 1 above */ ".previous \n" /* back in text section */ ".section __ex_table,\"a\"\n" /* start __extable */ " .align 8 \n" " .quad 0b,2b \n" /* failure point 0, fixup code 2 */ ".previous \n" : "=d" (cc) : "d" (real_page_addr), "d" (xpage_index) : "cc", "1", "2" );#endif /* CONFIG_ARCH_S390X */ switch (cc) { case 0: return 0; case 1: return -EIO; case 2: { PRINT_ERR("expanded storage lost!\n"); return -ENXIO; } case 3: return -ENXIO; default: return -EIO; /* should not happen */ }}/*--------------------------------------------------------------------*//* Measure expanded memory *//* Return value *//* size of expanded memory in kB (must be a multipe of 4) *//*--------------------------------------------------------------------*/int xpram_size(void){ int cc=0; unsigned long base=0; unsigned long po, pi, rpi; /* page index order, page index */ unsigned long mem_page = __get_free_page(GFP_KERNEL); /* for po=0,1,2,... try to move in page number base+(2^po)-1 */ pi=1; for (po=0; po <= 32; po++) { /* pi = 2^po */ cc=xpram_page_in(mem_page,base+pi-1); if ( cc ) break; pi <<= 1; } if ( cc && (po < 31 ) ) { pi >>=1; base += pi; pi >>=1; for ( ; pi > 0; pi >>= 1) { rpi = pi - 1; cc=xpram_page_in(mem_page,base+rpi); if ( !cc ) base += pi; } } free_page (mem_page); if ( cc && (po < 31) ) return (XPRAM_KB_IN_PG * base); else /* return maximal value possible */ return INT_MAX;}/* * Open and close */int xpram_open (struct inode *inode, struct file *filp){ Xpram_Dev *dev; /* device information */ int num = MINOR(inode->i_rdev); if (num >= xpram_devs) return -ENODEV; dev = xpram_devices + num; PRINT_DEBUG("calling xpram_open for device %d\n",num); PRINT_DEBUG(" size %dkB, name %s, usage: %d\n", dev->size,dev->device_name, atomic_read(&(dev->usage))); atomic_inc(&(dev->usage)); return 0; /* success */}int xpram_release (struct inode *inode, struct file *filp){ Xpram_Dev *dev = xpram_devices + MINOR(inode->i_rdev); PRINT_DEBUG("calling xpram_release for device %d (size %dkB, usage: %d)\n",MINOR(inode->i_rdev) ,dev->size,atomic_read(&(dev->usage))); /* * If the device is closed for the last time, start a timer * to release RAM in half a minute. The function and argument * for the timer have been setup in init_module() */ if (!atomic_dec_return(&(dev->usage))) { /* but flush it right now */ /* Everything is already flushed by caller -- AV */ } return(0);}/* * The ioctl() implementation */int xpram_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ int err, size; struct hd_geometry *geo = (struct hd_geometry *)arg; PRINT_DEBUG("ioctl 0x%x 0x%lx\n", cmd, arg); switch(cmd) { case BLKGETSIZE: /* 0x1260 */ /* Return the device size, expressed in sectors */ return put_user( 1024* xpram_sizes[MINOR(inode->i_rdev)] / XPRAM_SOFTSECT, (unsigned long *) arg); case BLKGETSIZE64: return put_user( (u64)(1024* xpram_sizes[MINOR(inode->i_rdev)] / XPRAM_SOFTSECT) << 9, (u64 *) arg); case BLKFLSBUF: /* flush, 0x1261 */ fsync_dev(inode->i_rdev); if ( capable(CAP_SYS_ADMIN) )invalidate_buffers(inode->i_rdev); return 0; case BLKRAGET: /* return the readahead value, 0x1263 */ if (!arg) return -EINVAL; err = 0; /* verify_area_20(VERIFY_WRITE, (long *) arg, sizeof(long)); * if (err) return err; */ put_user(read_ahead[MAJOR(inode->i_rdev)], (long *)arg); return 0; case BLKRASET: /* set the readahead value, 0x1262 */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (arg > 0xff) return -EINVAL; /* limit it */ read_ahead[MAJOR(inode->i_rdev)] = arg; atomic_eieio(); return 0; case BLKRRPART: /* re-read partition table: can't do it, 0x1259 */ return -EINVAL;#if (XPRAM_VERSION == 22) RO_IOCTLS(inode->i_rdev, arg); /* the default RO operations * BLKROSET * BLKROGET */#endif /* V22 */ case HDIO_GETGEO: /* * get geometry: we have to fake one... trim the size to a * multiple of 64 (32k): tell we have 16 sectors, 4 heads, * whatever cylinders. Tell also that data starts at sector. 4. */ size = xpram_mem_avail * 1024 / XPRAM_SOFTSECT; /* size = xpram_mem_avail * 1024 / xpram_hardsect; */ size &= ~0x3f; /* multiple of 64 */ if (geo==NULL) return -EINVAL; /* * err=verify_area_20(VERIFY_WRITE, geo, sizeof(*geo)); * if (err) return err; */ put_user(size >> 6, &geo->cylinders); put_user( 4, &geo->heads); put_user( 16, &geo->sectors); put_user( 4, &geo->start); return 0; } return -EINVAL; /* unknown command */}/* * The file operations */#if (XPRAM_VERSION == 22)struct file_operations xpram_fops = { NULL, /* lseek: default */ block_read, block_write, NULL, /* xpram_readdir */ NULL, /* xpram_select */ xpram_ioctl, NULL, /* xpram_mmap */ xpram_open, NULL, /* flush */ xpram_release, block_fsync, NULL, /* xpram_fasync */ NULL, NULL};#endif /* V22 */#if (XPRAM_VERSION == 24)struct block_device_operations xpram_devops ={ owner: THIS_MODULE, ioctl: xpram_ioctl, open: xpram_open, release: xpram_release,};#endif /* V24 *//* * Block-driver specific functions */void xpram_request(request_queue_t * queue){ Xpram_Dev *device; /* u8 *ptr; */ /* int size; */ unsigned long page_no; /* expanded memory page number */ unsigned long sects_to_copy; /* number of sectors to be copied */ char * buffer; /* local pointer into buffer cache */ int dev_no; /* device number of request */ int fault; /* faulty access to expanded memory */#if ( XPRAM_VERSION == 24 ) struct request * current_req; /* working request */#else # define current_req CURRENT#endif /* V24 */ while(1) { INIT_REQUEST; fault=0;#if ( XPRAM_VERSION == 24 ) current_req = blkdev_entry_next_request (&queue->queue_head);#endif /* V24 */ dev_no = DEVICE_NR(current_req->rq_dev); /* Check if the minor number is in range */ if ( dev_no > xpram_devs ) { static int count = 0; if (count++ < 5) /* print the message at most five times */ PRINT_WARN(" request for unknown device\n"); end_request(0); continue; } /* pointer to device structure, from the global array */ device = xpram_devices + dev_no; sects_to_copy = current_req->current_nr_sectors; /* does request exceed size of device ? */ if ( XPRAM_SEC2KB(sects_to_copy) > xpram_sizes[dev_no] ) { PRINT_WARN(" request past end of device\n"); end_request(0); continue; } /* Does request start at page boundery? -- paranoia */#if 0 PRINT_DEBUG(" req %lx, sect %lx, to copy %lx, buf addr %lx\n", (unsigned long) current_req, current_req->sector, sects_to_copy, (unsigned long) current_req->buffer);#endif buffer = current_req->buffer;#if XPRAM_SEC_IN_PG != 1 /* Does request start at an expanded storage page boundery? */ if ( current_req->sector & (XPRAM_SEC_IN_PG - 1) ) { PRINT_WARN(" request does not start at an expanded storage page boundery\n"); PRINT_WARN(" referenced sector: %ld\n",current_req->sector); end_request(0); continue; } /* Does request refere to partial expanded storage pages? */ if ( sects_to_copy & (XPRAM_SEC_IN_PG - 1) ) { PRINT_WARN(" request referes to a partial expanded storage page\n"); end_request(0); continue; }#endif /* XPRAM_SEC_IN_PG != 1 */ /* Is request buffer aligned with kernel pages? */ if ( ((unsigned long)buffer) & (XPRAM_PGSIZE-1) ) { PRINT_WARN(" request buffer is not aligned with kernel pages\n"); end_request(0); continue; } /* which page of expanded storage is affected first? */ page_no = (xpram_offsets[dev_no] >> XPRAM_KB_IN_PG_ORDER) + (current_req->sector >> XPRAM_SEC_IN_PG_ORDER); #if 0 PRINT_DEBUG("request: %d ( dev %d, copy %d sectors, at page %d ) \n", current_req->cmd,dev_no,sects_to_copy,page_no);#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -