/*===========================================================================* * m_transfer * *===========================================================================*/ static int m_transfer( endpoint_t endpt, /* endpoint of grant owner */ int opcode, /* DEV_GATHER_S or DEV_SCATTER_S */ u64_t pos64, /* offset on device to read or write */ iovec_t *iov, /* pointer to read or write request vector */ unsigned int nr_req, /* length of request vector */ endpoint_t UNUSED(user_endpt),/* endpoint of user process */ unsigned int UNUSED(flags) ) { /* Read or write one the driver's character devices. */ unsigned count, left, chunk; vir_bytes vir_offset = 0; struct device *dv; unsigned long dv_size; int s, r; off_t position; cp_grant_id_t grant; vir_bytes dev_vaddr; /* ZERO_DEV and NULL_DEV are infinite in size. */ if (m_device != ZERO_DEV && m_device != NULL_DEV && ex64hi(pos64) != 0) return OK; /* Beyond EOF */ position= cv64ul(pos64); /* Get minor device number and check for /dev/null. */ dv = &m_geom[m_device]; dv_size = cv64ul(dv->dv_size); dev_vaddr = m_vaddrs[m_device]; while (nr_req > 0) { /* How much to transfer and where to / from. */ count = iov->iov_size; grant = (cp_grant_id_t) iov->iov_addr; switch (m_device) { /* No copying; ignore request. */ case NULL_DEV: if (opcode == DEV_GATHER_S) return(OK); /* always at EOF */ break; /* Virtual copying. For kernel memory. */ default: case KMEM_DEV: if(!dev_vaddr || dev_vaddr == (vir_bytes) MAP_FAILED) { printf("MEM: dev %d not initialized\n", m_device); return EIO; } if (position >= dv_size) return(OK); /* check for EOF */ if (position + count > dv_size) count = dv_size - position; if (opcode == DEV_GATHER_S) { /* copy actual data */ r=sys_safecopyto(endpt, grant, vir_offset, dev_vaddr + position, count); } else { r=sys_safecopyfrom(endpt, grant, vir_offset, dev_vaddr + position, count); } if(r != OK) { panic("I/O copy failed: %d", r); } break; /* Physical copying. Only used to access entire memory. * Transfer one 'page window' at a time. */ case MEM_DEV: { u32_t pagestart, page_off; static u32_t pagestart_mapped; static int any_mapped = 0; static char *vaddr; int r; u32_t subcount; phys_bytes mem_phys; if (position >= dv_size) return(OK); /* check for EOF */ if (position + count > dv_size) count = dv_size - position; mem_phys = position; page_off = mem_phys % PAGE_SIZE; pagestart = mem_phys - page_off; /* All memory to the map call has to be page-aligned. * Don't have to map same page over and over. */ if(!any_mapped || pagestart_mapped != pagestart) { if(any_mapped) { if(vm_unmap_phys(SELF, vaddr, PAGE_SIZE) != OK) panic("vm_unmap_phys failed"); any_mapped = 0; } vaddr = vm_map_phys(SELF, (void *) pagestart, PAGE_SIZE); if(vaddr == MAP_FAILED) r = ENOMEM; else r = OK; if(r != OK) { printf("memory: vm_map_phys failed\n"); return r; } any_mapped = 1; pagestart_mapped = pagestart; } /* how much to be done within this page. */ subcount = PAGE_SIZE-page_off; if(subcount > count) subcount = count; if (opcode == DEV_GATHER_S) { /* copy data */ s=sys_safecopyto(endpt, grant, vir_offset, (vir_bytes) vaddr+page_off, subcount); } else { s=sys_safecopyfrom(endpt, grant, vir_offset, (vir_bytes) vaddr+page_off, subcount); } if(s != OK) return s; count = subcount; break; } /* Null byte stream generator. */ case ZERO_DEV: if (opcode == DEV_GATHER_S) { size_t suboffset = 0; left = count; while (left > 0) { chunk = (left > ZERO_BUF_SIZE) ? ZERO_BUF_SIZE : left; s=sys_safecopyto(endpt, grant, vir_offset+suboffset, (vir_bytes) dev_zero, chunk); if(s != OK) return s; left -= chunk; suboffset += chunk; } } break; } /* Book the number of bytes transferred. */ position += count; vir_offset += count; if ((iov->iov_size -= count) == 0) { iov++; nr_req--; vir_offset = 0; } } return(OK); }
/*===========================================================================* * m_block_transfer * *===========================================================================*/ static int m_block_transfer( dev_t minor, /* minor device number */ int do_write, /* read or write? */ u64_t pos64, /* offset on device to read or write */ endpoint_t endpt, /* process doing the request */ iovec_t *iov, /* pointer to read or write request vector */ unsigned int nr_req, /* length of request vector */ int UNUSED(flags) /* transfer flags */ ) { /* Read or write one the driver's block devices. */ unsigned count; vir_bytes vir_offset = 0; struct device *dv; unsigned long dv_size; int r; off_t position; vir_bytes dev_vaddr; cp_grant_id_t grant; ssize_t total = 0; /* Get minor device information. */ if ((dv = m_block_part(minor)) == NULL) return(ENXIO); dv_size = cv64ul(dv->dv_size); dev_vaddr = m_vaddrs[minor]; if (ex64hi(pos64) != 0) return OK; /* Beyond EOF */ position= cv64ul(pos64); while (nr_req > 0) { /* How much to transfer and where to / from. */ count = iov->iov_size; grant = (cp_grant_id_t) iov->iov_addr; /* Virtual copying. For RAM disks and internal FS. */ if(!dev_vaddr || dev_vaddr == (vir_bytes) MAP_FAILED) { printf("MEM: dev %d not initialized\n", minor); return EIO; } if (position >= dv_size) return(total); /* check for EOF */ if (position + count > dv_size) count = dv_size - position; if (!do_write) { /* copy actual data */ r=sys_safecopyto(endpt, grant, vir_offset, dev_vaddr + position, count); } else { r=sys_safecopyfrom(endpt, grant, vir_offset, dev_vaddr + position, count); } if(r != OK) { panic("I/O copy failed: %d", r); } /* Book the number of bytes transferred. */ position += count; vir_offset += count; total += count; if ((iov->iov_size -= count) == 0) { iov++; nr_req--; vir_offset = 0; } } return(total); }
int main(int argc, char **argv) { int first; int i; char *file; unsigned long offset, size, devsize; int fd; struct stat st; ssize_t r; struct super_block super; swap_hdr_t swap_hdr; u8_t block[BLOCK_SIZE]; first= 0; i= 1; while (i < argc && argv[i][0] == '-') { char *opt= argv[i++]+1; if (opt[0] == '-' && opt[1] == 0) break; /* -- */ while (*opt != 0) switch (*opt++) { case 'f': first= 1; break; default: usage(); } } if (i == argc) usage(); file= argv[i++]; size= 0; if (i < argc) { char *end; unsigned long m; size= strtoul(argv[i], &end, 10); if (end == argv[i]) usage(); m= 1024; if (*end != 0) { switch (*end) { case 'm': case 'M': m *= 1024; /*FALL THROUGH*/ case 'k': case 'K': end++; break; } } if (*end != 0 || size == -1 || (size * m) / m != size || (size *= m) <= SWAP_OFFSET ) { fprintf(stderr, "mkswap: %s: Bad size\n", argv[i]); exit(1); } i++; } if (i != argc) usage(); /* Open the device or file. */ if ((fd= open(file, O_RDWR | O_CREAT | O_TRUNC, 0600)) < 0) { fprintf(stderr, "mkswap: Can't open %s: %s\n", file, strerror(errno)); exit(1); } /* File or device? */ (void) fstat(fd, &st); if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)) { struct partition part; /* How big is the partition? */ if (ioctl(fd, DIOCGETP, &part) < 0) { fprintf(stderr, "mkswap: Can't determine the size of %s: %s\n", file, strerror(errno)); exit(1); } devsize= cv64ul(part.size); offset= 0; if (!first) { /* Is there a file system? */ r= -1; if (lseek(fd, SUPER_BLOCK * BLOCK_SIZE, SEEK_SET) == -1 || (r= read(fd, block, BLOCK_SIZE)) < BLOCK_SIZE ) { fprintf(stderr, "mkswap: %s: %s\n", file, r >= 0 ? "End of file" : strerror(errno)); exit(1); } memcpy(&super, block, sizeof(super)); if (super.s_magic == SUPER_MAGIC) { offset= (unsigned long) super.s_nzones * BLOCK_SIZE; } else if (super.s_magic == SUPER_V2) { offset= (unsigned long) super.s_zones * BLOCK_SIZE; } else { first= 1; } } if (size == 0) size= devsize - offset; if (size == 0 || offset + size > devsize) { fprintf(stderr, "mkswap: There is no room on %s for ", file); if (size > 0) fprintf(stderr, "%lu kilobytes of ", size/1024); fprintf(stderr, "swapspace\n"); if (offset > 0) { fprintf(stderr, "(Use the -f flag to wipe the file system)\n"); } exit(1); } } else if (S_ISREG(st.st_mode)) { /* Write to the swap file to guarantee space for MM. */ unsigned long n; if (size == 0) { fprintf(stderr, "mkswap: No size specified for %s\n", file); usage(); } memset(block, 0, sizeof(block)); for (n= 0; n < size; n += r) { r= size > sizeof(block) ? sizeof(block) : size; if ((r= write(fd, block, r)) <= 0) { fprintf(stderr, "mkswap: %s: %s\n", file, r == 0 ? "End of file" : strerror(errno)); exit(1); } } first= 1; } else { fprintf(stderr, "mkswap: %s is not a device or a file\n", file); exit(1); } if (offset < SWAP_OFFSET) { offset += SWAP_OFFSET; if (size < SWAP_OFFSET) size= 0; else size -= SWAP_OFFSET; } swap_hdr.sh_magic[0]= SWAP_MAGIC0; swap_hdr.sh_magic[1]= SWAP_MAGIC1; swap_hdr.sh_magic[2]= SWAP_MAGIC2; swap_hdr.sh_magic[3]= SWAP_MAGIC3; swap_hdr.sh_version= SH_VERSION; swap_hdr.sh_priority= 0; swap_hdr.sh_offset= offset; swap_hdr.sh_swapsize= size; r= -1; if (lseek(fd, SWAP_BOOTOFF, SEEK_SET) == -1 || (r= read(fd, block, sizeof(block))) < BLOCK_SIZE ) { fprintf(stderr, "mkswap: %s: %s\n", file, file, r >= 0 ? "End of file" : strerror(errno)); exit(1); } r= (first ? SWAP_BOOTOFF : OPTSWAP_BOOTOFF) - SWAP_BOOTOFF; memcpy(block + r, &swap_hdr, sizeof(swap_hdr)); r= -1; if (lseek(fd, SWAP_BOOTOFF, SEEK_SET) == -1 || (r= write(fd, block, sizeof(block))) < BLOCK_SIZE ) { fprintf(stderr, "mkswap: %s: %s\n", file, file, r >= 0 ? "End of file" : strerror(errno)); exit(1); } printf("%s: swapspace at offset %lu, size %lu kilobytes\n", file, offset / 1024, size / 1024); return 0; }