1 /* This file contains the device dependent part of the drivers for the 2 * following special files: 3 * /dev/ram - RAM disk 4 * /dev/mem - absolute memory 5 * /dev/kmem - kernel virtual memory 6 * /dev/null - null device (data sink) 7 * /dev/boot - boot device loaded from boot image 8 * /dev/zero - null byte stream generator 9 * /dev/imgrd - boot image RAM disk 10 * 11 * Changes: 12 * Apr 29, 2005 added null byte generator (Jorrit N. Herder) 13 * Apr 09, 2005 added support for boot device (Jorrit N. Herder) 14 * Jul 26, 2004 moved RAM driver to user-space (Jorrit N. Herder) 15 * Apr 20, 1992 device dependent/independent split (Kees J. Bot) 16 */ 17 18 #include <assert.h> 19 #include <minix/drivers.h> 20 #include <minix/chardriver.h> 21 #include <minix/blockdriver.h> 22 #include <sys/ioc_memory.h> 23 #include <minix/ds.h> 24 #include <minix/vm.h> 25 #include <machine/param.h> 26 #include <machine/vmparam.h> 27 #include <sys/mman.h> 28 #include "kernel/const.h" 29 #include "kernel/config.h" 30 #include "kernel/type.h" 31 32 #include <machine/vm.h> 33 34 #include "local.h" 35 36 /* ramdisks (/dev/ram*) */ 37 #define RAMDISKS 6 38 39 #define RAM_DEV_LAST (RAM_DEV_FIRST+RAMDISKS-1) 40 41 #define NR_DEVS (7+RAMDISKS) /* number of minor devices */ 42 43 static struct device m_geom[NR_DEVS]; /* base and size of each device */ 44 static vir_bytes m_vaddrs[NR_DEVS]; 45 46 static int openct[NR_DEVS]; 47 48 static ssize_t m_char_read(devminor_t minor, u64_t position, endpoint_t endpt, 49 cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); 50 static ssize_t m_char_write(devminor_t minor, u64_t position, endpoint_t endpt, 51 cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); 52 static int m_char_open(devminor_t minor, int access, endpoint_t user_endpt); 53 static int m_char_close(devminor_t minor); 54 55 static struct device *m_block_part(devminor_t minor); 56 static ssize_t m_block_transfer(devminor_t minor, int do_write, u64_t position, 57 endpoint_t endpt, iovec_t *iov, unsigned int nr_req, int flags); 58 static int m_block_open(devminor_t minor, int access); 59 static int m_block_close(devminor_t minor); 60 static int m_block_ioctl(devminor_t minor, unsigned long request, endpoint_t 61 endpt, cp_grant_id_t grant, endpoint_t user_endpt); 62 63 /* Entry points to the CHARACTER part of this driver. */ 64 static struct chardriver m_cdtab = { 65 .cdr_open = m_char_open, /* open device */ 66 .cdr_close = m_char_close, /* close device */ 67 .cdr_read = m_char_read, /* read from device */ 68 .cdr_write = m_char_write /* write to device */ 69 }; 70 71 /* Entry points to the BLOCK part of this driver. */ 72 static struct blockdriver m_bdtab = { 73 .bdr_type = BLOCKDRIVER_TYPE_DISK,/* handle partition requests */ 74 .bdr_open = m_block_open, /* open device */ 75 .bdr_close = m_block_close, /* nothing on a close */ 76 .bdr_transfer = m_block_transfer, /* do the I/O */ 77 .bdr_ioctl = m_block_ioctl, /* ram disk I/O control */ 78 .bdr_part = m_block_part /* return partition information */ 79 }; 80 81 /* SEF functions and variables. */ 82 static void sef_local_startup(void); 83 static int sef_cb_init_fresh(int type, sef_init_info_t *info); 84 85 /*===========================================================================* 86 * main * 87 *===========================================================================*/ 88 int main(void) 89 { 90 message msg; 91 int r, ipc_status; 92 93 /* SEF local startup. */ 94 sef_local_startup(); 95 96 /* The receive loop. */ 97 for (;;) { 98 if ((r = driver_receive(ANY, &msg, &ipc_status)) != OK) 99 panic("memory: driver_receive failed (%d)", r); 100 101 if (IS_BDEV_RQ(msg.m_type)) 102 blockdriver_process(&m_bdtab, &msg, ipc_status); 103 else 104 chardriver_process(&m_cdtab, &msg, ipc_status); 105 } 106 107 return(OK); 108 } 109 110 /*===========================================================================* 111 * sef_local_startup * 112 *===========================================================================*/ 113 static void sef_local_startup() 114 { 115 /* Register init callbacks. */ 116 sef_setcb_init_fresh(sef_cb_init_fresh); 117 sef_setcb_init_lu(sef_cb_init_fresh); 118 sef_setcb_init_restart(sef_cb_init_fresh); 119 120 /* Register live update callbacks. */ 121 sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready); 122 sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_standard); 123 124 /* Let SEF perform startup. */ 125 sef_startup(); 126 } 127 128 /*===========================================================================* 129 * sef_cb_init_fresh * 130 *===========================================================================*/ 131 static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) 132 { 133 /* Initialize the memory driver. */ 134 int i; 135 #if 0 136 struct kinfo kinfo; /* kernel information */ 137 int s; 138 139 if (OK != (s=sys_getkinfo(&kinfo))) { 140 panic("Couldn't get kernel information: %d", s); 141 } 142 143 /* Map in kernel memory for /dev/kmem. */ 144 m_geom[KMEM_DEV].dv_base = kinfo.kmem_base; 145 m_geom[KMEM_DEV].dv_size = kinfo.kmem_size; 146 if((m_vaddrs[KMEM_DEV] = vm_map_phys(SELF, (void *) kinfo.kmem_base, 147 kinfo.kmem_size)) == MAP_FAILED) { 148 printf("MEM: Couldn't map in /dev/kmem."); 149 } 150 #endif 151 152 /* Ramdisk image built into the memory driver */ 153 m_geom[IMGRD_DEV].dv_base= 0; 154 m_geom[IMGRD_DEV].dv_size= imgrd_size; 155 m_vaddrs[IMGRD_DEV] = (vir_bytes) imgrd; 156 157 for(i = 0; i < NR_DEVS; i++) 158 openct[i] = 0; 159 160 /* Set up memory range for /dev/mem. */ 161 m_geom[MEM_DEV].dv_base = 0; 162 m_geom[MEM_DEV].dv_size = 0xffffffffULL; 163 164 m_vaddrs[MEM_DEV] = (vir_bytes) MAP_FAILED; /* we are not mapping this in. */ 165 166 return(OK); 167 } 168 169 /*===========================================================================* 170 * m_is_block * 171 *===========================================================================*/ 172 static int m_is_block(devminor_t minor) 173 { 174 /* Return TRUE iff the given minor device number is for a block device. */ 175 176 switch (minor) { 177 case MEM_DEV: 178 case KMEM_DEV: 179 case NULL_DEV: 180 case ZERO_DEV: 181 return FALSE; 182 183 default: 184 return TRUE; 185 } 186 } 187 188 /*===========================================================================* 189 * m_transfer_kmem * 190 *===========================================================================*/ 191 static ssize_t m_transfer_kmem(devminor_t minor, int do_write, u64_t position, 192 endpoint_t endpt, cp_grant_id_t grant, size_t size) 193 { 194 /* Transfer from or to the KMEM device. */ 195 u64_t dv_size, dev_vaddr; 196 int r; 197 198 dv_size = m_geom[minor].dv_size; 199 dev_vaddr = m_vaddrs[minor]; 200 201 if (!dev_vaddr || dev_vaddr == (vir_bytes) MAP_FAILED) { 202 printf("MEM: dev %d not initialized\n", minor); 203 return EIO; 204 } 205 206 if (position >= dv_size) return 0; /* check for EOF */ 207 if (position + size > dv_size) size = dv_size - position; 208 209 if (!do_write) /* copy actual data */ 210 r = sys_safecopyto(endpt, grant, 0, dev_vaddr + position, size); 211 else 212 r = sys_safecopyfrom(endpt, grant, 0, dev_vaddr + position, size); 213 214 return (r != OK) ? r : size; 215 } 216 217 /*===========================================================================* 218 * m_transfer_mem * 219 *===========================================================================*/ 220 static ssize_t m_transfer_mem(devminor_t minor, int do_write, u64_t position, 221 endpoint_t endpt, cp_grant_id_t grant, size_t size) 222 { 223 /* Transfer from or to the MEM device. */ 224 static int any_mapped = 0; 225 static phys_bytes pagestart_mapped; 226 static char *vaddr; 227 phys_bytes mem_phys, pagestart; 228 size_t off, page_off, subcount; 229 u64_t dv_size; 230 int r; 231 232 dv_size = m_geom[minor].dv_size; 233 if (position >= dv_size) return 0; /* check for EOF */ 234 if (position + size > dv_size) size = dv_size - position; 235 236 /* Physical copying. Only used to access entire memory. 237 * Transfer one 'page window' at a time. 238 */ 239 off = 0; 240 while (off < size) { 241 mem_phys = (phys_bytes) position; 242 243 page_off = (size_t) (mem_phys % PAGE_SIZE); 244 pagestart = mem_phys - page_off; 245 246 /* All memory to the map call has to be page-aligned. 247 * Don't have to map same page over and over. 248 */ 249 if (!any_mapped || pagestart_mapped != pagestart) { 250 if (any_mapped) { 251 if (vm_unmap_phys(SELF, vaddr, PAGE_SIZE) != OK) 252 panic("vm_unmap_phys failed"); 253 any_mapped = 0; 254 } 255 256 vaddr = vm_map_phys(SELF, (void *) pagestart, PAGE_SIZE); 257 if (vaddr == MAP_FAILED) { 258 printf("memory: vm_map_phys failed\n"); 259 return ENOMEM; 260 } 261 any_mapped = 1; 262 pagestart_mapped = pagestart; 263 } 264 265 /* how much to be done within this page. */ 266 subcount = PAGE_SIZE - page_off; 267 if (subcount > size) 268 subcount = size; 269 270 if (!do_write) /* copy data */ 271 r = sys_safecopyto(endpt, grant, off, 272 (vir_bytes) vaddr + page_off, subcount); 273 else 274 r = sys_safecopyfrom(endpt, grant, off, 275 (vir_bytes) vaddr + page_off, subcount); 276 if (r != OK) 277 return r; 278 279 position += subcount; 280 off += subcount; 281 } 282 283 return off; 284 } 285 286 /*===========================================================================* 287 * m_char_read * 288 *===========================================================================*/ 289 static ssize_t m_char_read(devminor_t minor, u64_t position, endpoint_t endpt, 290 cp_grant_id_t grant, size_t size, int UNUSED(flags), 291 cdev_id_t UNUSED(id)) 292 { 293 /* Read from one of the driver's character devices. */ 294 ssize_t r; 295 296 /* Check if the minor device number is ok. */ 297 if (minor < 0 || minor >= NR_DEVS || m_is_block(minor)) return ENXIO; 298 299 switch (minor) { 300 case NULL_DEV: 301 r = 0; /* always at EOF */ 302 break; 303 304 case ZERO_DEV: 305 /* Fill the target area with zeroes. In fact, let the kernel do it! */ 306 if ((r = sys_safememset(endpt, grant, 0, '\0', size)) == OK) 307 r = size; 308 break; 309 310 case KMEM_DEV: 311 r = m_transfer_kmem(minor, FALSE, position, endpt, grant, size); 312 break; 313 314 case MEM_DEV: 315 r = m_transfer_mem(minor, FALSE, position, endpt, grant, size); 316 break; 317 318 default: 319 panic("unknown character device %d", minor); 320 } 321 322 return r; 323 } 324 325 /*===========================================================================* 326 * m_char_write * 327 *===========================================================================*/ 328 static ssize_t m_char_write(devminor_t minor, u64_t position, endpoint_t endpt, 329 cp_grant_id_t grant, size_t size, int UNUSED(flags), 330 cdev_id_t UNUSED(id)) 331 { 332 /* Write to one of the driver's character devices. */ 333 ssize_t r; 334 335 /* Check if the minor device number is ok. */ 336 if (minor < 0 || minor >= NR_DEVS || m_is_block(minor)) return ENXIO; 337 338 switch (minor) { 339 case NULL_DEV: 340 case ZERO_DEV: 341 r = size; /* just eat everything */ 342 break; 343 344 case KMEM_DEV: 345 r = m_transfer_kmem(minor, TRUE, position, endpt, grant, size); 346 break; 347 348 case MEM_DEV: 349 r = m_transfer_mem(minor, TRUE, position, endpt, grant, size); 350 break; 351 352 default: 353 panic("unknown character device %d", minor); 354 } 355 356 return r; 357 } 358 359 /*===========================================================================* 360 * m_char_open * 361 *===========================================================================*/ 362 static int m_char_open(devminor_t minor, int access, endpoint_t user_endpt) 363 { 364 /* Open a memory character device. */ 365 366 /* Check if the minor device number is ok. */ 367 if (minor < 0 || minor >= NR_DEVS || m_is_block(minor)) return ENXIO; 368 369 #if defined(__i386__) 370 if (minor == MEM_DEV) 371 { 372 int r = sys_enable_iop(user_endpt); 373 if (r != OK) 374 { 375 printf("m_char_open: sys_enable_iop failed for %d: %d\n", 376 user_endpt, r); 377 return r; 378 } 379 } 380 #endif 381 382 openct[minor]++; 383 384 return(OK); 385 } 386 387 /*===========================================================================* 388 * m_char_close * 389 *===========================================================================*/ 390 static int m_char_close(devminor_t minor) 391 { 392 /* Close a memory character device. */ 393 394 if (minor < 0 || minor >= NR_DEVS || m_is_block(minor)) return ENXIO; 395 396 if(openct[minor] < 1) { 397 printf("MEMORY: closing unopened device %d\n", minor); 398 return(EINVAL); 399 } 400 openct[minor]--; 401 402 return(OK); 403 } 404 405 /*===========================================================================* 406 * m_block_part * 407 *===========================================================================*/ 408 static struct device *m_block_part(devminor_t minor) 409 { 410 /* Prepare for I/O on a device: check if the minor device number is ok. */ 411 if (minor < 0 || minor >= NR_DEVS || !m_is_block(minor)) return(NULL); 412 413 return(&m_geom[minor]); 414 } 415 416 /*===========================================================================* 417 * m_block_transfer * 418 *===========================================================================*/ 419 static int m_block_transfer( 420 devminor_t minor, /* minor device number */ 421 int do_write, /* read or write? */ 422 u64_t position, /* offset on device to read or write */ 423 endpoint_t endpt, /* process doing the request */ 424 iovec_t *iov, /* pointer to read or write request vector */ 425 unsigned int nr_req, /* length of request vector */ 426 int UNUSED(flags) /* transfer flags */ 427 ) 428 { 429 /* Read or write one the driver's block devices. */ 430 unsigned count; 431 vir_bytes vir_offset = 0; 432 struct device *dv; 433 u64_t dv_size; 434 int r; 435 vir_bytes dev_vaddr; 436 cp_grant_id_t grant; 437 ssize_t total = 0; 438 439 /* Get minor device information. */ 440 if ((dv = m_block_part(minor)) == NULL) return(ENXIO); 441 dv_size = dv->dv_size; 442 dev_vaddr = m_vaddrs[minor]; 443 444 if (ex64hi(position) != 0) 445 return OK; /* Beyond EOF */ 446 447 while (nr_req > 0) { 448 449 /* How much to transfer and where to / from. */ 450 count = iov->iov_size; 451 grant = (cp_grant_id_t) iov->iov_addr; 452 453 /* Virtual copying. For RAM disks and internal FS. */ 454 if(!dev_vaddr || dev_vaddr == (vir_bytes) MAP_FAILED) { 455 printf("MEM: dev %d not initialized\n", minor); 456 return EIO; 457 } 458 if (position >= dv_size) return(total); /* check for EOF */ 459 if (position + count > dv_size) count = dv_size - position; 460 if (!do_write) { /* copy actual data */ 461 r=sys_safecopyto(endpt, grant, vir_offset, 462 dev_vaddr + position, count); 463 } else { 464 r=sys_safecopyfrom(endpt, grant, vir_offset, 465 dev_vaddr + position, count); 466 } 467 if(r != OK) { 468 panic("I/O copy failed: %d", r); 469 } 470 471 /* Book the number of bytes transferred. */ 472 position += count; 473 vir_offset += count; 474 total += count; 475 if ((iov->iov_size -= count) == 0) { iov++; nr_req--; vir_offset = 0; } 476 477 } 478 return(total); 479 } 480 481 /*===========================================================================* 482 * m_block_open * 483 *===========================================================================*/ 484 static int m_block_open(devminor_t minor, int UNUSED(access)) 485 { 486 /* Open a memory block device. */ 487 if (m_block_part(minor) == NULL) return(ENXIO); 488 489 openct[minor]++; 490 491 return(OK); 492 } 493 494 /*===========================================================================* 495 * m_block_close * 496 *===========================================================================*/ 497 static int m_block_close(devminor_t minor) 498 { 499 /* Close a memory block device. */ 500 if (m_block_part(minor) == NULL) return(ENXIO); 501 502 if(openct[minor] < 1) { 503 printf("MEMORY: closing unopened device %d\n", minor); 504 return(EINVAL); 505 } 506 openct[minor]--; 507 508 return(OK); 509 } 510 511 /*===========================================================================* 512 * m_block_ioctl * 513 *===========================================================================*/ 514 static int m_block_ioctl(devminor_t minor, unsigned long request, 515 endpoint_t endpt, cp_grant_id_t grant, endpoint_t UNUSED(user_endpt)) 516 { 517 /* I/O controls for the block devices of the memory driver. Currently there is 518 * one I/O control specific to the memory driver: 519 * - MIOCRAMSIZE: to set the size of the RAM disk. 520 */ 521 struct device *dv; 522 u32_t ramdev_size; 523 int s; 524 void *mem; 525 int is_imgrd = 0; 526 527 if (request != MIOCRAMSIZE) 528 return EINVAL; 529 530 if(minor == IMGRD_DEV) 531 is_imgrd = 1; 532 533 /* Someone wants to create a new RAM disk with the given size. 534 * A ramdisk can be created only once, and only on RAM disk device. 535 */ 536 if ((dv = m_block_part(minor)) == NULL) return ENXIO; 537 if((minor < RAM_DEV_FIRST || minor > RAM_DEV_LAST) && 538 minor != RAM_DEV_OLD && !is_imgrd) { 539 printf("MEM: MIOCRAMSIZE: %d not a ramdisk\n", minor); 540 return EINVAL; 541 } 542 543 /* Get request structure */ 544 s= sys_safecopyfrom(endpt, grant, 0, (vir_bytes)&ramdev_size, 545 sizeof(ramdev_size)); 546 if (s != OK) 547 return s; 548 if(is_imgrd) 549 ramdev_size = 0; 550 if(m_vaddrs[minor] && dv->dv_size == (u64_t) ramdev_size) { 551 return(OK); 552 } 553 /* openct is 1 for the ioctl(). */ 554 if(openct[minor] != 1) { 555 printf("MEM: MIOCRAMSIZE: %d in use (count %d)\n", 556 minor, openct[minor]); 557 return(EBUSY); 558 } 559 if(m_vaddrs[minor]) { 560 u32_t a, o; 561 u64_t size; 562 int r; 563 if(ex64hi(dv->dv_size)) { 564 panic("huge old ramdisk"); 565 } 566 size = dv->dv_size; 567 a = m_vaddrs[minor]; 568 if((o = a % PAGE_SIZE)) { 569 vir_bytes l = PAGE_SIZE - o; 570 a += l; 571 size -= l; 572 } 573 size = rounddown(size, PAGE_SIZE); 574 r = munmap((void *) a, size); 575 if(r != OK) { 576 printf("memory: WARNING: munmap failed: %d\n", r); 577 } 578 m_vaddrs[minor] = (vir_bytes) NULL; 579 dv->dv_size = 0; 580 } 581 582 #if DEBUG 583 printf("MEM:%d: allocating ramdisk of size 0x%x\n", minor, ramdev_size); 584 #endif 585 586 mem = NULL; 587 588 /* Try to allocate a piece of memory for the RAM disk. */ 589 if(ramdev_size > 0 && 590 (mem = mmap(NULL, ramdev_size, PROT_READ|PROT_WRITE, 591 MAP_PREALLOC|MAP_ANON, -1, 0)) == MAP_FAILED) { 592 printf("MEM: failed to get memory for ramdisk\n"); 593 return(ENOMEM); 594 } 595 596 m_vaddrs[minor] = (vir_bytes) mem; 597 598 dv->dv_size = ramdev_size; 599 600 return(OK); 601 } 602