ext2.c (19048B)
1 /* 2 * core/ext2.c 3 * 4 * Copyright (C) 2009 stateless 5 */ 6 7 #include <ext2.h> 8 #include <common.h> 9 #include <errno.h> 10 #include <string.h> 11 #include <heap.h> 12 #include <x86.h> 13 #include <mm.h> 14 #include <syscall.h> 15 #include <elf.h> 16 #include <tty.h> 17 #include <unistd.h> 18 #include <pipe.h> 19 20 #define EXT2_SETERRNO_AND_RET(err, ret) SETERRNO_AND_RET(err, ret) 21 22 spinlock_t flist_lock; 23 struct list_head flist; 24 25 static struct ext2_superblock_t *sblock = NULL; 26 static struct ext2_inode_t *root_inode = NULL; 27 static char *fs_base_addr = NULL; 28 29 static void *readblock(uint32_t block_no); 30 static struct ext2_inode_t *geti(ino_t ino); 31 static struct ext2_gdt_t *readgdt(uint32_t gdt); 32 static int read_inode_blocks(struct ext2_inode_t *inode, off_t offs, char *buffer, size_t nbytes); 33 static int check_inode_status(ino_t inode); 34 static struct ext2_dir_t *resolve_path_internal(struct ext2_inode_t *inode, const char *path); 35 static struct ext2_dir_t *resolve_path(const char *path); 36 static struct ext2_dir_t *find_dentry(struct ext2_inode_t *inode, const char *name, uint32_t is_root); 37 static int filealloc(ino_t inode_nr); 38 static blksize_t get_block_size(void); 39 40 static blksize_t 41 get_block_size(void) 42 { 43 assert(sblock); 44 return 1024 << sblock->block_size; 45 } 46 47 static inline void * 48 readblock(uint32_t block_no) 49 { 50 assert(sblock); 51 return fs_base_addr + get_block_size() * block_no; 52 } 53 54 static inline struct ext2_gdt_t * 55 readgdt(uint32_t gdt) { 56 char *block; 57 58 block = readblock(2); 59 return (struct ext2_gdt_t *)(block + (gdt * sizeof(struct ext2_gdt_t))); 60 } 61 62 static inline struct ext2_inode_t * 63 geti(ino_t ino) { 64 struct ext2_gdt_t *gdt; 65 66 gdt = readgdt((ino - 1) / sblock->nr_inodes_per_group); 67 return (struct ext2_inode_t *)((char *)readblock(gdt->addr_inode_table) + (ino - 1) * sblock->inode_size); 68 } 69 70 /* should be called with flist_lock held */ 71 __attribute__ ((unused)) static void 72 dump_flist(void) 73 { 74 struct list_head *iter; 75 struct file_t *f; 76 77 list_for_each(iter, &flist) { 78 f = list_entry(iter, struct file_t, f_listopen); 79 printf("inode = 0x%08lx, off = %lu, state = %s, ref_count = %d\n", 80 (void *)f->f_inode, 81 f->f_off, 82 (f->f_state == FILE_ALLOC) ? "FILE_ALLOC" : "FILE_NONE", 83 f->f_refcount 84 ); 85 } 86 } 87 88 int 89 ext2_mount(char *addr) 90 { 91 int i; 92 93 if (!addr) return -EINVAL; 94 fs_base_addr = addr; 95 sblock = (struct ext2_superblock_t *)(fs_base_addr + 1024); 96 if (sblock->magic != 0xef53) { 97 info("invalid ext2 volume!\n"); 98 sblock = NULL; 99 return -EILSEQ; 100 } 101 root_inode = geti(2); 102 if (!(root_inode->file_mode & DIRECTORY_T)) { 103 info("can't locate the root directory of the filesystem!\n"); 104 return -ENOTDIR; 105 } 106 for (i = 1; i <= 10; ++i) 107 if (check_inode_status(i) < 0) { 108 info("inode validation failed!\n"); 109 return -EIO; 110 } 111 INIT_LIST_HEAD(&flist); 112 initspinlock(&flist_lock); 113 return 0; 114 } 115 116 struct ext2_inode_t * 117 get_root_inode(void) { 118 assert(root_inode); 119 return root_inode; 120 } 121 122 static int 123 read_inode_blocks(struct ext2_inode_t *inode, off_t offs /* in blocks */, char *buffer, size_t nbytes) 124 { 125 int ret = -EINVAL, off = 0; 126 uint32_t *block, i; 127 blkcnt_t nr_blocks; 128 blksize_t blksize; 129 char *tmp; 130 131 if (!inode || !buffer) 132 return ret; 133 if (!nbytes) 134 return 0; 135 136 /* TODO: make sure this code is bug-proof */ 137 blksize = get_block_size(); 138 nr_blocks = inode->size_low32 / blksize; 139 if (nr_blocks >= 12 + (blksize / 4) 140 || (nbytes / blksize) + offs >= 12 + (blksize / 4)) { 141 info("can't handle double indirect blocks yet!\n"); 142 return -EIO; 143 } 144 if (offs >= 12) { 145 offs -= 12; 146 goto read_indirect; 147 } 148 block = (uint32_t *)inode->direct_blocks; 149 block += offs; 150 for (i = offs / blksize; nbytes && i <= nr_blocks; ++i, ++block) { 151 if (!*block) 152 continue; 153 tmp = readblock(*block); 154 memcpy((char *)buffer + off, tmp, blksize); 155 nbytes -= blksize; 156 off += blksize; 157 if (off / blksize >= 12 && nbytes) 158 goto read_indirect; 159 } 160 if (!nbytes) return off; 161 read_indirect: 162 block = (uint32_t *)readblock(inode->single_indir_block); 163 block += offs; 164 for (i = offs / blksize; nbytes && i <= nr_blocks; ++i, ++block) { 165 if (!*block) 166 continue; 167 tmp = readblock(*block); 168 memcpy((char *)buffer + off, tmp, blksize); 169 nbytes -= blksize; 170 off += blksize; 171 } 172 return off; 173 } 174 175 static struct ext2_dir_t * 176 find_dentry(struct ext2_inode_t *inode, const char *name, uint32_t is_root) { 177 char *buffer; 178 struct ext2_dir_t *dir, *retdir; 179 int ret; 180 blkcnt_t nr_blocks; 181 blksize_t blksize; 182 183 if (!name) 184 return ERR_PTR(-EINVAL); 185 186 blksize = get_block_size(); 187 buffer = kmalloc(blksize); 188 if (IS_ERR(buffer)) 189 return (void *)buffer; 190 nr_blocks = inode->size_low32 / blksize; 191 for (uint32_t j = 0; j <= nr_blocks; ++j) { 192 if ((ret = read_inode_blocks(inode, j, buffer, blksize)) < 0) 193 kerror(-ret); 194 if (!ret) continue; 195 dir = (struct ext2_dir_t *)buffer; 196 if (is_root) goto found; 197 for (; dir->rec_length; 198 dir = (struct ext2_dir_t *)((char *)dir + dir->rec_length)) { 199 if (strlen(name) == dir->name_length) { 200 if (!strncmp(name, dir->filename, dir->name_length)) { 201 found: 202 if (is_root) 203 assert(!strcmp(name, "/")); 204 retdir = kmalloc(sizeof(*retdir)); 205 if (IS_ERR(retdir)) { 206 kfree(buffer); 207 return retdir; 208 } 209 memcpy(retdir, dir, sizeof(*retdir)); 210 kfree(buffer); 211 return retdir; 212 } 213 } 214 } 215 } 216 kfree(buffer); 217 return ERR_PTR(-ENOENT); 218 } 219 220 static int 221 filealloc(ino_t inode_nr) 222 { 223 struct ext2_inode_t *inode; 224 struct file_t *f; 225 int i; 226 227 inode = geti(inode_nr); 228 acquire(&flist_lock); 229 for (i = 3; i < NR_MAX_OPEN_FILES; ++i) { 230 if (curr_proc->fdtable[i] 231 && curr_proc->fdtable[i]->f_state != FILE_NONE) 232 continue; 233 if (!curr_proc->fdtable[i]) { 234 f = kmalloc(sizeof(struct file_t)); 235 if (IS_ERR(f)) { 236 release(&flist_lock); 237 return PTR_ERR(f); 238 } 239 f->f_state = FILE_NONE; 240 list_add_tail(&f->f_listopen, &flist); 241 curr_proc->fdtable[i] = f; 242 } 243 f = curr_proc->fdtable[i]; 244 assert(f->f_state == FILE_NONE); 245 f->f_refcount = 1; 246 f->f_off = 0; 247 f->f_state = FILE_ALLOC; 248 f->f_type = FILE_REG; 249 f->f_inode = inode; 250 f->f_inode_nr = inode_nr; 251 release(&flist_lock); 252 return i; 253 } 254 release(&flist_lock); 255 return -EMFILE; 256 } 257 258 int 259 fileclose(int fd) 260 { 261 struct file_t *f; 262 int j; 263 264 if (fd < 0 || fd >= NR_MAX_OPEN_FILES) 265 return -EINVAL; 266 267 acquire(&flist_lock); 268 f = curr_proc->fdtable[fd]; 269 if (!f || f->f_state != FILE_ALLOC) { 270 release(&flist_lock); 271 return -EBADF; 272 } 273 if (!--f->f_refcount) { 274 curr_proc->fdtable[fd]->f_state = FILE_NONE; 275 if (f->f_type == FILE_PIPE) { 276 for (j = 3; j < NR_MAX_OPEN_FILES; ++j) { 277 if (fd == j || curr_proc->pipebufs[j] != curr_proc->pipebufs[fd]) 278 continue; 279 if (curr_proc->fdtable[j]->f_state == FILE_ALLOC) 280 break; 281 /* no one is referencing this buffer */ 282 kfree(curr_proc->pipebufs[fd]); 283 curr_proc->pipebufs[fd] = curr_proc->pipebufs[j] = NULL; 284 break; 285 } 286 } 287 } 288 release(&flist_lock); 289 return 0; 290 } 291 292 /* TODO: free pipebufs */ 293 void 294 closefds(void) 295 { 296 struct file_t *f; 297 int i; 298 299 acquire(&flist_lock); 300 for (i = 3; i < NR_MAX_OPEN_FILES; ++i) { 301 if (!curr_proc->fdtable[i]) 302 continue; 303 f = curr_proc->fdtable[i]; 304 if (f->f_state == FILE_NONE || f->f_state == FILE_ALLOC) { 305 if (f->f_state == FILE_NONE) { 306 assert(!f->f_refcount); 307 list_del(&f->f_listopen); 308 /* invalidate dup(2)ed close fds */ 309 bzero(f, sizeof(*f)); 310 kfree(f); 311 } else { 312 if (!--f->f_refcount) { 313 list_del(&f->f_listopen); 314 bzero(f, sizeof(*f)); 315 kfree(f); 316 } 317 } 318 } 319 } 320 release(&flist_lock); 321 } 322 323 static struct ext2_dir_t * 324 resolve_path_internal(struct ext2_inode_t *inode, const char *path) { 325 struct ext2_dir_t *dirent; 326 char *buf, *bufptr; 327 const char *ptr; 328 uint32_t ino; 329 uint32_t is_root_flag = 1; 330 int ret; 331 332 buf = kmalloc(EXT2_NAME_LEN + 1); 333 if (IS_ERR(buf)) { 334 ret = PTR_ERR(buf); 335 return ERR_PTR(ret); 336 } 337 memset(buf, 0, EXT2_NAME_LEN + 1); 338 ptr = path; 339 *buf = *ptr; 340 if (*ptr == '/') ++ptr; 341 if (*ptr) { 342 bufptr = buf; 343 while (*ptr && *ptr != '/') { 344 if (bufptr - buf >= EXT2_NAME_LEN) { 345 kfree(buf); 346 return ERR_PTR(-ENAMETOOLONG); 347 } 348 *bufptr++ = *ptr++; 349 } 350 if (*ptr == '/') ++ptr; 351 is_root_flag = 0; 352 } 353 if (IS_ERR(dirent = find_dentry(inode, buf, is_root_flag))) { 354 ret = PTR_ERR(dirent); 355 goto err; 356 } 357 kfree(buf); 358 if (!*ptr) 359 return dirent; 360 ino = dirent->inode; 361 kfree(dirent); 362 return resolve_path_internal(geti(ino), ptr); 363 err: 364 kfree(buf); 365 return ERR_PTR(ret); 366 } 367 368 static struct ext2_dir_t * 369 resolve_path(const char *path) { 370 if (!path) 371 return NULL; 372 if (*path == '/') 373 return resolve_path_internal(root_inode, path); 374 return resolve_path_internal(curr_proc->cdir, path); 375 } 376 377 static int 378 check_inode_status(ino_t inode) 379 { 380 struct ext2_gdt_t *gdt; 381 char *inode_bitmap; 382 blksize_t i; 383 384 gdt = readgdt((inode - 1) / sblock->nr_inodes_per_group); 385 inode_bitmap = readblock(gdt->addr_block_bitmap); 386 for (i = 0; i < get_block_size(); ++i) 387 if (inode_bitmap[i / 8] & (1 << (1 % 8))) 388 return 0; 389 return -ENOENT; 390 } 391 392 int 393 dup(int oldfd) 394 { 395 int i; 396 struct file_t *f, *tmp; 397 398 if (oldfd < 0 || oldfd >= NR_MAX_OPEN_FILES) 399 return -EINVAL; 400 acquire(&flist_lock); 401 f = curr_proc->fdtable[oldfd]; 402 if (!f || f->f_state != FILE_ALLOC) { 403 release(&flist_lock); 404 return -EBADF; 405 } 406 for (i = 3; i < NR_MAX_OPEN_FILES; ++i) { 407 tmp = curr_proc->fdtable[i]; 408 if (!tmp || tmp->f_state == FILE_NONE) { 409 if (tmp->f_state == FILE_NONE) { 410 assert(!tmp->f_refcount); 411 list_del(&tmp->f_listopen); 412 kfree(tmp); 413 tmp = NULL; 414 } 415 curr_proc->fdtable[i] = f; 416 ++f->f_refcount; 417 release(&flist_lock); 418 return i; 419 } 420 } 421 release(&flist_lock); 422 return -EMFILE; 423 } 424 425 int 426 dup2(int oldfd, int newfd) 427 { 428 struct file_t *f, *tmp; 429 430 if (oldfd < 0 || oldfd >= NR_MAX_OPEN_FILES) 431 return -EINVAL; 432 acquire(&flist_lock); 433 f = curr_proc->fdtable[oldfd]; 434 if (!f || f->f_state != FILE_ALLOC 435 || newfd < 0 || newfd >= NR_MAX_OPEN_FILES) { 436 release(&flist_lock); 437 return -EBADF; 438 } 439 if (oldfd == newfd) { 440 release(&flist_lock); 441 return newfd; 442 } 443 tmp = curr_proc->fdtable[newfd]; 444 if (tmp && tmp->f_state == FILE_ALLOC) 445 if (!--tmp->f_refcount) 446 tmp->f_state = FILE_NONE; 447 if (tmp) 448 assert(!tmp->f_refcount); 449 if (!tmp || !tmp->f_refcount) { 450 curr_proc->fdtable[newfd] = f; 451 ++f->f_refcount; 452 release(&flist_lock); 453 return newfd; 454 } 455 release(&flist_lock); 456 return -EMFILE; 457 } 458 459 int 460 open(const char *pathname, 461 __attribute__ ((unused)) int flags, 462 __attribute__ ((unused)) mode_t mode) 463 { 464 struct ext2_dir_t *dirent; 465 int fd; 466 467 if (!pathname) 468 return -EINVAL; 469 dirent = resolve_path(pathname); 470 if (IS_ERR(dirent)) 471 return PTR_ERR(dirent); 472 fd = filealloc(dirent->inode); 473 return fd; 474 } 475 476 int 477 creat(__attribute__ ((unused)) const char *pathname, 478 __attribute__ ((unused)) mode_t mode) 479 { 480 return -ENOSYS; 481 } 482 483 int 484 close(int fd) 485 { 486 return fileclose(fd); 487 } 488 489 DIR * 490 opendir(const char *name) 491 { 492 int fd; 493 DIR *newdir = NULL; 494 495 fd = sys_open(name, 0, 0); 496 if (fd < 0) 497 EXT2_SETERRNO_AND_RET(-fd, NULL); 498 if (!(curr_proc->fdtable[fd]->f_inode->file_mode & DIRECTORY_T)) { 499 errno = ENOTDIR; 500 goto err; 501 } 502 newdir = kmalloc(sizeof(*newdir)); 503 if (IS_ERR(newdir)) { 504 errno = -PTR_ERR(newdir); 505 goto err; 506 } 507 newdir->off = 0; 508 newdir->fd = fd; 509 return newdir; 510 err: 511 sys_close(fd); 512 EXT2_SETERRNO_AND_RET(errno, NULL); 513 } 514 515 struct dirent_t * 516 readdir(DIR *dirp) { 517 struct file_t *file; 518 static struct dirent_t dirent; 519 struct ext2_dir_t *dir; 520 struct ext2_inode_t *inode; 521 char *buffer; 522 blksize_t blksize; 523 int ret; 524 525 if (!dirp) 526 return ERR_PTR(-EINVAL); 527 file = curr_proc->fdtable[dirp->fd]; 528 if (!file || !(file->f_inode->file_mode & DIRECTORY_T)) 529 return ERR_PTR(-EINVAL); 530 inode = geti(file->f_inode_nr); 531 blksize = get_block_size(); 532 buffer = kmalloc(blksize); 533 if (IS_ERR(buffer)) 534 return (void *)buffer; 535 /* TODO: make it possible to have directory entries spanning many blocks */ 536 ret = read_inode_blocks(inode, 0, buffer, blksize); 537 if (ret <= 0) { 538 kfree(buffer); 539 return ERR_PTR(ret); 540 } 541 dir = (struct ext2_dir_t *)(buffer + dirp->off); 542 if (dirp->off >= blksize) { 543 kfree(buffer); 544 return NULL; 545 } 546 dirp->off += dir->rec_length; 547 dirent.d_inode = dir->inode; 548 dirent.d_off = (uint32_t)((char *)dir - buffer); 549 dirent.d_namelen = dir->name_length; 550 memset(dirent.d_name, 0, EXT2_NAME_LEN + 1); 551 memcpy(dirent.d_name, dir->filename, dir->name_length); 552 kfree(buffer); 553 return &dirent; 554 } 555 556 int 557 closedir(DIR *dirp) 558 { 559 int ret; 560 561 if (!dirp) 562 return -EINVAL; 563 if ((ret = sys_close(dirp->fd)) < 0) 564 return ret; 565 kfree(dirp); 566 return 0; 567 } 568 569 ssize_t 570 read(int fd, void *buf, size_t count) 571 { 572 struct file_t *f; 573 int ret; 574 char *newbuf; 575 size_t newcnt; 576 blksize_t blksize; 577 off_t soff; 578 ssize_t r; 579 580 581 if (fd < 0 || fd >= NR_MAX_OPEN_FILES || !buf) 582 return -EINVAL; 583 584 if (fd == STDIN_FILENO) 585 return tty_read(buf, count); 586 587 acquire(&flist_lock); 588 f = curr_proc->fdtable[fd]; 589 if (!f || f->f_state != FILE_ALLOC) { 590 release(&flist_lock); 591 return -EBADF; 592 } 593 if (f->f_type == FILE_PIPE) { 594 r = piperead(fd, buf, count); 595 release(&flist_lock); 596 return r; 597 } 598 assert(f->f_inode); 599 if (f->f_inode->file_mode & DIRECTORY_T) { 600 release(&flist_lock); 601 return -EISDIR; 602 } 603 blksize = get_block_size(); 604 if (f->f_inode->size_low32 - f->f_off < count) 605 count = f->f_inode->size_low32 - f->f_off; 606 if (!count) goto out; 607 newcnt = count; 608 if (newcnt % blksize) newcnt = (newcnt + blksize) & ~(blksize - 1); 609 newbuf = kmalloc(newcnt); 610 if (IS_ERR(newbuf)) { 611 release(&flist_lock); 612 return PTR_ERR(newbuf); 613 } 614 soff = (f->f_off % blksize) ? (f->f_off & ~((off_t)blksize - 1)) : (off_t)f->f_off; 615 soff /= blksize; 616 if ((ret = read_inode_blocks(f->f_inode, soff, newbuf, newcnt)) <= 0) { 617 kfree(newbuf); 618 release(&flist_lock); 619 return ret; 620 } 621 soff = f->f_off % newcnt; 622 if (newcnt - soff < count) count = newcnt - soff; 623 memcpy(buf, newbuf + soff, count); 624 f->f_off += count; 625 kfree(newbuf); 626 out: 627 release(&flist_lock); 628 return count; 629 } 630 631 ssize_t 632 write(int fd, const void *buf, size_t count) 633 { 634 const char *ptr; 635 size_t len = 0; 636 struct file_t *f; 637 ssize_t r; 638 639 if (fd < 0 || fd >= NR_MAX_OPEN_FILES || !buf) 640 return -EINVAL; 641 642 /* ignore STDIN, STDOUT and STDERR for now */ 643 if (fd > 2) { 644 acquire(&flist_lock); 645 f = curr_proc->fdtable[fd]; 646 if (!f || f->f_state != FILE_ALLOC) { 647 release(&flist_lock); 648 return -EBADF; 649 } 650 if (f->f_type == FILE_PIPE) { 651 r = pipewrite(fd, buf, count); 652 release(&flist_lock); 653 return r; 654 } 655 release(&flist_lock); 656 } 657 ptr = buf; 658 while (count--) { 659 if (putchar(*ptr++) < 0) 660 break; 661 ++len; 662 } 663 return len; 664 } 665 666 int 667 stat(const char *path, struct stat *buf) 668 { 669 struct ext2_dir_t *dir; 670 struct ext2_inode_t *inode; 671 672 if (!path || !buf) 673 return -EINVAL; 674 675 dir = resolve_path(path); 676 if (IS_ERR(dir)) 677 return PTR_ERR(dir); 678 inode = geti(dir->inode); 679 buf->st_dev = 0; 680 buf->st_ino = dir->inode; 681 buf->st_mode = inode->file_mode; 682 buf->st_nlink = inode->link_count; 683 buf->st_uid = inode->uid_low16 | (inode->uid_upper16 << 16); 684 buf->st_gid = inode->gid_low16 | (inode->gid_upper16 << 16); 685 buf->st_rdev = 0; 686 buf->st_size = inode->size_low32; 687 buf->st_blksize = get_block_size(); 688 buf->st_blocks = (inode->size_low32 / buf->st_blksize) * (buf->st_blksize / 512); 689 buf->st_atime = inode->atime; 690 buf->st_mtime = inode->mtime; 691 buf->st_ctime = inode->ctime; 692 return 0; 693 } 694 695 int 696 fstat(int fd, struct stat *buf) 697 { 698 struct file_t *f; 699 struct ext2_inode_t *inode; 700 701 if (fd < 0 || fd >= NR_MAX_OPEN_FILES) 702 return -EBADF; 703 if (!buf) 704 return -EINVAL; 705 acquire(&flist_lock); 706 f = curr_proc->fdtable[fd]; 707 if (!f || f->f_state != FILE_ALLOC) { 708 release(&flist_lock); 709 return -EBADF; 710 } 711 inode = geti(f->f_inode_nr); 712 buf->st_dev = 0; 713 buf->st_ino = f->f_inode_nr; 714 buf->st_mode = inode->file_mode; 715 buf->st_nlink = inode->link_count; 716 buf->st_uid = inode->uid_low16 | (inode->uid_upper16 << 16); 717 buf->st_gid = inode->gid_low16 | (inode->gid_upper16 << 16); 718 buf->st_rdev = 0; 719 buf->st_size = inode->size_low32; 720 buf->st_blksize = get_block_size(); 721 buf->st_blocks = (inode->size_low32 / buf->st_blksize) * (buf->st_blksize / 512); 722 buf->st_atime = inode->atime; 723 buf->st_mtime = inode->mtime; 724 buf->st_ctime = inode->ctime; 725 release(&flist_lock); 726 return 0; 727 } 728 729 int 730 execve(const char *filename, 731 __attribute__ ((unused)) char *const argv[], 732 __attribute__ ((unused)) char *const envp[]) 733 { 734 struct stat buf; 735 int fd, ret = 0, i; 736 char *elfimage; 737 ssize_t bytesleft; 738 ssize_t bytesread = 0; 739 Elf32_Ehdr *elfheader; 740 Elf32_Phdr *elfprog; 741 uint32_t sz; 742 struct mmap_region *reg; 743 struct list_head *iter, *tmpreg; 744 size_t len; 745 blksize_t blksize; 746 747 if ((fd = open(filename, O_RDONLY, 0)) < 0) 748 return fd; 749 if ((ret = fstat(fd, &buf)) < 0) 750 goto err; 751 if (IS_ERR(elfimage = kmalloc(buf.st_size))) { 752 ret = PTR_ERR(elfimage); 753 goto err; 754 } 755 756 bytesleft = buf.st_size; 757 blksize = get_block_size(); 758 do { 759 ret = read(fd, elfimage + bytesread, bytesleft); 760 if (!ret) break; 761 if (ret < 0) goto err1; 762 bytesread += ret; 763 bytesleft -= ret; 764 } while (bytesleft > 0); 765 assert(!bytesleft && bytesread == buf.st_size); 766 elfheader = (Elf32_Ehdr *)elfimage; 767 768 if (elfheader->e_ident[EI_MAG0] != 0x7f 769 || elfheader->e_ident[EI_MAG1] != 'E' 770 || elfheader->e_ident[EI_MAG2] != 'L' 771 || elfheader->e_ident[EI_MAG3] != 'F' 772 || elfheader->e_type != ET_EXEC 773 || elfheader->e_machine != EM_386 774 || !elfheader->e_entry 775 || elfheader->e_version != EV_CURRENT 776 || elfheader->e_ident[EI_VERSION] != EV_CURRENT 777 || !elfheader->e_phnum 778 || elfheader->e_ident[EI_CLASS] != ELFCLASS32 779 || elfheader->e_ident[EI_DATA] != ELFDATA2LSB) { 780 ret = -ENOEXEC; 781 goto err1; 782 } 783 784 elfprog = (Elf32_Phdr *)(elfimage + elfheader->e_phoff); 785 for (i = 0; i < elfheader->e_phnum; ++i, ++elfprog) { 786 if (elfprog->p_type != 0x1) continue; 787 if (elfprog->p_vaddr + elfprog->p_memsz < elfprog->p_vaddr) 788 goto err1; 789 sz = elfprog->p_filesz; 790 reg = kmalloc(sizeof(*reg)); 791 if (IS_ERR(reg)) { 792 ret = PTR_ERR(reg); 793 goto err1; 794 } 795 if ((ret = mmap_range(elfprog->p_vaddr, elfprog->p_vaddr + sz)) < 0) { 796 for (--elfprog; i > 0; --i) { 797 ret = unmap_range(elfprog->p_vaddr, elfprog->p_vaddr + sz); 798 if (ret < 0) 799 panic("can't unmap mapped pages!"); 800 } 801 kfree(reg); 802 goto err2; 803 } 804 bzero((void *)elfprog->p_vaddr, 0); 805 memcpy((void *)elfprog->p_vaddr, 806 (const void *)(elfimage + elfprog->p_offset), sz); 807 reg->base_addr = elfprog->p_vaddr; reg->size = sz; 808 list_add_tail(®->l_region, &curr_proc->l_regions); 809 } 810 811 kfree(curr_proc->name); 812 len = strlen(filename) + 1; 813 assert(len); 814 curr_proc->name = kmalloc(len); 815 if (IS_ERR(curr_proc->name)) { 816 ret = PTR_ERR(curr_proc->name); 817 goto err2; 818 } 819 strncpy(curr_proc->name, filename, len); 820 curr_proc->name[len - 1] = '\0'; 821 curr_proc->cf->eip = elfheader->e_entry; 822 goto err1; 823 err2: 824 list_for_each_safe(iter, tmpreg, &curr_proc->l_regions) { 825 reg = list_entry(iter, struct mmap_region, l_region); 826 if (unmap_range(reg->base_addr, reg->base_addr + reg->size) < 0) 827 panic("failed to unmap pages!"); 828 list_del(iter); 829 kfree(reg); 830 } 831 err1: 832 kfree(elfimage); 833 err: 834 close(fd); 835 return ret; 836 } 837