Welcome to The Fiwix Project
A UNIX-like kernel for the i386 architecture
1 /* 2 * fiwix/drivers/block/ramdisk.c 3 * 4 * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved. 5 * Distributed under the terms of the Fiwix License. 6 */ 7 8 #include <fiwix/kernel.h> 9 #include <fiwix/ramdisk.h> 10 #include <fiwix/ioctl.h> 11 #include <fiwix/devices.h> 12 #include <fiwix/part.h> 13 #include <fiwix/fs.h> 14 #include <fiwix/errno.h> 15 #include <fiwix/mm.h> 16 #include <fiwix/stdio.h> 17 #include <fiwix/string.h> 18 19 struct ramdisk ramdisk_table[RAMDISK_MINORS]; 20 static unsigned int rd_sizes[256]; 21 22 static struct fs_operations ramdisk_driver_fsop = { 23 0, 24 0, 25 26 ramdisk_open, 27 ramdisk_close, 28 NULL, /* read */ 29 NULL, /* write */ 30 ramdisk_ioctl, 31 ramdisk_lseek, 32 NULL, /* readdir */ 33 NULL, /* mmap */ 34 NULL, /* select */ 35 36 NULL, /* readlink */ 37 NULL, /* followlink */ 38 NULL, /* bmap */ 39 NULL, /* lockup */ 40 NULL, /* rmdir */ 41 NULL, /* link */ 42 NULL, /* unlink */ 43 NULL, /* symlink */ 44 NULL, /* mkdir */ 45 NULL, /* mknod */ 46 NULL, /* truncate */ 47 NULL, /* create */ 48 NULL, /* rename */ 49 50 ramdisk_read, 51 ramdisk_write, 52 53 NULL, /* read_inode */ 54 NULL, /* write_inode */ 55 NULL, /* ialloc */ 56 NULL, /* ifree */ 57 NULL, /* statfs */ 58 NULL, /* read_superblock */ 59 NULL, /* remount_fs */ 60 NULL, /* write_superblock */ 61 NULL /* release_superblock */ 62 }; 63 64 static struct device ramdisk_device = { 65 "ramdisk", 66 RAMDISK_MAJOR, 67 { 0, 0, 0, 0, 0, 0, 0, 0 }, 68 BLKSIZE_1K, 69 &rd_sizes, 70 &ramdisk_driver_fsop, 71 NULL 72 }; 73 74 static struct ramdisk * get_ramdisk(int minor) 75 { 76 if(TEST_MINOR(ramdisk_device.minors, minor)) { 77 return &ramdisk_table[minor]; 78 } 79 return NULL; 80 } 81 82 int ramdisk_open(struct inode *i, struct fd *fd_table) 83 { 84 if(!get_ramdisk(MINOR(i->rdev))) { 85 return -ENXIO; 86 } 87 return 0; 88 } 89 90 int ramdisk_close(struct inode *i, struct fd *fd_table) 91 { 92 if(!get_ramdisk(MINOR(i->rdev))) { 93 return -ENXIO; 94 } 95 return 0; 96 } 97 98 int ramdisk_read(__dev_t dev, __blk_t block, char *buffer, int blksize) 99 { 100 int size; 101 __off_t offset; 102 struct ramdisk *ramdisk; 103 104 if(!(ramdisk = get_ramdisk(MINOR(dev)))) { 105 return -ENXIO; 106 } 107 108 size = rd_sizes[MINOR(dev)] * 1024; 109 offset = block * blksize; 110 if(offset > size) { 111 printk("%s(): block %d is beyond the size of the ramdisk.\n", __FUNCTION__, block); 112 return -EIO; 113 } 114 blksize = MIN(blksize, size - offset); 115 memcpy_b((void *)buffer, ramdisk->addr + offset, blksize); 116 return blksize; 117 } 118 119 int ramdisk_write(__dev_t dev, __blk_t block, char *buffer, int blksize) 120 { 121 int size; 122 __off_t offset; 123 struct ramdisk *ramdisk; 124 125 if(!(ramdisk = get_ramdisk(MINOR(dev)))) { 126 return -ENXIO; 127 } 128 129 size = rd_sizes[MINOR(dev)] * 1024; 130 offset = block * blksize; 131 if(offset > size) { 132 printk("%s(): block %d is beyond the size of the ramdisk.\n", __FUNCTION__, block); 133 return -EIO; 134 } 135 blksize = MIN(blksize, size - offset); 136 memcpy_b(ramdisk->addr + offset, buffer, blksize); 137 return blksize; 138 } 139 140 int ramdisk_ioctl(struct inode *i, int cmd, unsigned long int arg) 141 { 142 struct hd_geometry *geom; 143 int errno; 144 145 if(!get_ramdisk(MINOR(i->rdev))) { 146 return -ENXIO; 147 } 148 149 switch(cmd) { 150 case HDIO_GETGEO: 151 if((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(struct hd_geometry)))) { 152 return errno; 153 } 154 geom = (struct hd_geometry *)arg; 155 geom->heads = 63; 156 geom->sectors = 16; 157 geom->cylinders = rd_sizes[MINOR(i->rdev)] * 1024 / BPS; 158 geom->cylinders /= (geom->heads * geom->sectors); 159 geom->start = 0; 160 break; 161 case BLKRRPART: 162 break; 163 case BLKGETSIZE: 164 if((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned int)))) { 165 return errno; 166 } 167 *(int *)arg = rd_sizes[MINOR(i->rdev)] * 2; 168 break; 169 default: 170 return -EINVAL; 171 } 172 return 0; 173 } 174 175 int ramdisk_lseek(struct inode *i, __off_t offset) 176 { 177 return offset; 178 } 179 180 void ramdisk_init(void) 181 { 182 int n; 183 struct ramdisk *ramdisk; 184 185 if(!_noramdisk) { 186 for(n = 0; n < RAMDISK_MINORS; n++) { 187 SET_MINOR(ramdisk_device.minors, n); 188 rd_sizes[n] = _ramdisksize; 189 ramdisk = get_ramdisk(n); 190 printk("ram%d 0x%08X-0x%08X %d RAMdisk(s) of %dKB size, %dKB blocksize\n", n, ramdisk->addr, ramdisk->addr + (_ramdisksize * 1024), RAMDISK_MINORS, _ramdisksize, BLKSIZE_1K / 1024); 191 } 192 register_device(BLK_DEV, &ramdisk_device); 193 } 194 }