Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1292171
  • 博文数量: 196
  • 博客积分: 4141
  • 博客等级: 中将
  • 技术积分: 2253
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-21 20:04
文章存档

2019年(31)

2016年(1)

2014年(16)

2011年(8)

2010年(25)

2009年(115)

分类: 虚拟化

2009-03-22 16:52:58

591 static void handle_output(int fd, unsigned long dma, unsigned long key,
592 struct device_list *devices)
593 {
594 struct device *i;
595 u32 *lenp;
596 struct iovec iov[LGUEST_MAX_DMA_SECTIONS];
597 unsigned num = 0;
598
599 lenp = dma2iov(dma, iov, &num);
600 for (i = devices->dev; i; i = i->next) {
601 if (i->handle_output && key == i->watch_key) {
602 *lenp = i->handle_output(fd, iov, num, i);
603 return;
604 }
605 }
606 warnx("Pending dma %p, key %p", (void *)dma, (void *)key);
607 }
608
609 static void handle_input(int fd, struct device_list *devices)
610 {
611 struct timeval poll = { .tv_sec = 0, .tv_usec = 0 };
612
613 for (;;) {
614 struct device *i;
615 fd_set fds = devices->infds;
616
617 if (select(devices->max_infd+1, &fds, NULL, NULL, &poll) == 0)
618 break;
619
620 for (i = devices->dev; i; i = i->next) {
621 if (i->handle_input && FD_ISSET(i->fd, &fds)) {
622 if (!i->handle_input(fd, i)) {
623 FD_CLR(i->fd, &devices->infds);
624 /* Tell waker to ignore it too... */
625 write(waker_fd, &i->fd, sizeof(i->fd));
626 }
627 }
628 }
629 }
630 }
631
632 static struct lguest_device_desc *new_dev_desc(u16 type, u16 features,
633 u16 num_pages)
634 {
635 static unsigned long top = LGUEST_GUEST_TOP;
636 struct lguest_device_desc *desc;
637
638 desc = malloc(sizeof(*desc));
639 desc->type = type;
640 desc->num_pages = num_pages;
641 desc->features = features;
642 desc->status = 0;
643 if (num_pages) {
644 top -= num_pages*getpagesize();
645 map_zeroed_pages(top, num_pages);
646 desc->pfn = top / getpagesize();
647 } else
648 desc->pfn = 0;
649 return desc;
650 }
651
652 static struct device *new_device(struct device_list *devices,
653 u16 type, u16 num_pages, u16 features,
654 int fd,
655 bool (*handle_input)(int, struct device *),
656 unsigned long watch_off,
657 u32 (*handle_output)(int,
658 const struct iovec *,
659 unsigned,
660 struct device *))
661 {
662 struct device *dev = malloc(sizeof(*dev));
663
664 /* Append to device list. */
665 *devices->lastdev = dev;
666 dev->next = NULL;
667 devices->lastdev = &dev->next;
668
669 dev->fd = fd;
670 if (handle_input)
671 set_fd(dev->fd, devices);
672 dev->desc = new_dev_desc(type, features, num_pages);
673 dev->mem = (void *)(dev->desc->pfn * getpagesize());
674 dev->handle_input = handle_input;
675 dev->watch_key = (unsigned long)dev->mem + watch_off;
676 dev->handle_output = handle_output;
677 return dev;
678 }
679
680 static void setup_console(struct device_list *devices)
681 {
682 struct device *dev;
683
684 if (tcgetattr(STDIN_FILENO, &orig_term) == 0) {
685 struct termios term = orig_term;
686 term.c_lflag &= ~(ISIG|ICANON|ECHO);
687 tcsetattr(STDIN_FILENO, TCSANOW, &term);
                    // atexit - register a function to be called at normal process termination


688 atexit(restore_term);
689 }
690
691 /* We don't currently require a page for the console. */
692 dev = new_device(devices, LGUEST_DEVICE_T_CONSOLE, 0, 0,
693 STDIN_FILENO, handle_console_input,
694 LGUEST_CONSOLE_DMA_KEY, handle_console_output);
695 dev->priv = malloc(sizeof(struct console_abort));
696 ((struct console_abort *)dev->priv)->count = 0;
697 verbose("device %p: console\n",
698 (void *)(dev->desc->pfn * getpagesize()));
699 }
700
701 static void setup_block_file(const char *filename, struct device_list *devices)
702 {
703 int fd;
704 struct device *dev;
705 off64_t *device_len;
706 struct lguest_block_page *p;
707
708 fd = open_or_die(filename, O_RDWR|O_LARGEFILE|O_DIRECT);
709 dev = new_device(devices, LGUEST_DEVICE_T_BLOCK, 1,
710 LGUEST_DEVICE_F_RANDOMNESS,
711 fd, NULL, 0, handle_block_output);
712 device_len = dev->priv = malloc(sizeof(*device_len));
713 *device_len = lseek64(fd, 0, SEEK_END);
714 p = dev->mem;
715
716 p->num_sectors = *device_len/512;
717 verbose("device %p: block %i sectors\n",
718 (void *)(dev->desc->pfn * getpagesize()), p->num_sectors);
719 }
720
721 /* We use fnctl locks to reserve network slots (autocleanup!) */
722 static unsigned int find_slot(int netfd, const char *filename)
723 {
//struct flcok


//{


// short int l_type; /* 锁定的状态*/


//


// 这三个参数用于分段对文件加锁,若对整个文件加锁,则:l_whence=SEEK_SET,l_start=0,l_len=0;


// short int l_whence;/*决定l_start位置*/


// off_t l_start; /*锁定区域的开头位置*/


// off_t l_len; /*锁定区域的大小*/


// pid_t l_pid; /*锁定动作的进程*/


//};


//l_type 有三种状态:


//F_RDLCK 建立一个供读取用的锁定


//F_WRLCK 建立一个供写入用的锁定


//F_UNLCK 删除之前建立的锁定


 
//l_whence 也有三种方式:


//SEEK_SET 以文件开头为锁定的起始位置。


//SEEK_CUR 以目前文件读写位置为锁定的起始位置


//SEEK_END 以文件结尾为锁定的起始位置。


 
//返回值 成功则返回,若有错误则返回-1,错误原因存于errno.


724 struct flock fl;
725
726 fl.l_type = F_WRLCK;
727 fl.l_whence = SEEK_SET;
728 fl.l_len = 1;
729 for (fl.l_start = 0;
730 fl.l_start < getpagesize()/sizeof(struct lguest_net);
731 fl.l_start++) {
732 if (fcntl(netfd, F_SETLK, &fl) == 0)
733 return fl.l_start;
734 }
735 errx(1, "No free slots in network file %s", filename);
736 }
737
738 static void setup_net_file(const char *filename,
739 struct device_list *devices)
740 {
741 int netfd;
742 struct device *dev;
743
744 netfd = open(filename, O_RDWR, 0);
745 if (netfd < 0) {
746 if (errno == ENOENT) {
747 netfd = open(filename, O_RDWR|O_CREAT, 0600);
748 if (netfd >= 0) {
749 char page[getpagesize()];
750 memset(page, 0, sizeof(page));
751 write(netfd, page, sizeof(page));
752 }
753 }
754 if (netfd < 0)
755 err(1, "cannot open net file '%s'", filename);
756 }
757
758 dev = new_device(devices, LGUEST_DEVICE_T_NET, 1,
759 find_slot(netfd, filename)|LGUEST_NET_F_NOCSUM,
760 -1, NULL, 0, NULL);
761
762 /* We overwrite the /dev/zero mapping with the actual file. */
763 if (mmap(dev->mem, getpagesize(), PROT_READ|PROT_WRITE,
764 MAP_FIXED|MAP_SHARED, netfd, 0) != dev->mem)
765 err(1, "could not mmap '%s'", filename);
766 verbose("device %p: shared net %s, peer %i\n",
767 (void *)(dev->desc->pfn * getpagesize()), filename,
768 dev->desc->features & ~LGUEST_NET_F_NOCSUM);
769 }
770
771 static u32 str2ip(const char *ipaddr)
772 {
773 unsigned int byte[4];
774
775 sscanf(ipaddr, "%u.%u.%u.%u", &byte[0], &byte[1], &byte[2], &byte[3]);
776 return (byte[0] << 24) | (byte[1] << 16) | (byte[2] << 8) | byte[3];
777 }
778
779 /* adapted from libbridge */
780 static void add_to_bridge(int fd, const char *if_name, const char *br_name)
781 {
782 int ifidx;
    /*
     * Interface request structure used for socket
     * ioctl's. All interface ioctl's must have parameter
     * definitions which begin with ifr_name. The
     * remainder may be interface specific.
     */

783 struct ifreq ifr;
784
785 if (!*br_name)
786 errx(1, "must specify bridge name");
787
788 ifidx = if_nametoindex(if_name);
789 if (!ifidx)
790 errx(1, "interface %s does not exist!", if_name);
791
792 strncpy(ifr.ifr_name, br_name, IFNAMSIZ);
793 ifr.ifr_ifindex = ifidx;
794 if (ioctl(fd, SIOCBRADDIF, &ifr) < 0)
795 err(1, "can't add %s to bridge %s", if_name, br_name);
796 }
797
798 static void configure_device(int fd, const char *devname, u32 ipaddr,
799 unsigned char hwaddr[6])
800 {
801 struct ifreq ifr;
802 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
803
804 memset(&ifr, 0, sizeof(ifr));
805 strcpy(ifr.ifr_name, devname);
806 sin->sin_family = AF_INET;
807 sin->sin_addr.s_addr = htonl(ipaddr);
808 if (ioctl(fd, SIOCSIFADDR, &ifr) != 0)
809 err(1, "Setting %s interface address", devname);
810 ifr.ifr_flags = IFF_UP;
811 if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0)
812 err(1, "Bringing interface %s up", devname);
813
814 if (ioctl(fd, SIOCGIFHWADDR, &ifr) != 0)
815 err(1, "getting hw address for %s", devname);
816
817 memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, 6);
818 }
819
820 static void setup_tun_net(const char *arg, struct device_list *devices)
821 {
822 struct device *dev;
823 struct ifreq ifr;
824 int netfd, ipfd;
825 u32 ip;
826 const char *br_name = NULL;
827
828 netfd = open_or_die("/dev/net/tun", O_RDWR);
829 memset(&ifr, 0, sizeof(ifr));
830 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
831 strcpy(ifr.ifr_name, "tap%d");
832 if (ioctl(netfd, TUNSETIFF, &ifr) != 0)
833 err(1, "configuring /dev/net/tun");
834 ioctl(netfd, TUNSETNOCSUM, 1);
835
836 /* You will be peer 1: we should create enough jitter to randomize */
837 dev = new_device(devices, LGUEST_DEVICE_T_NET, 1,
838 NET_PEERNUM|LGUEST_DEVICE_F_RANDOMNESS, netfd,
839 handle_tun_input, peer_offset(0), handle_tun_output);
840 dev->priv = malloc(sizeof(bool));
841 *(bool *)dev->priv = false;
842
843 ipfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
844 if (ipfd < 0)
845 err(1, "opening IP socket");
846
847 if (!strncmp(BRIDGE_PFX, arg, strlen(BRIDGE_PFX))) {
848 ip = INADDR_ANY;
849 br_name = arg + strlen(BRIDGE_PFX);
850 add_to_bridge(ipfd, ifr.ifr_name, br_name);
851 } else
852 ip = str2ip(arg);
853
854 /* We are peer 0, ie. first slot. */
855 configure_device(ipfd, ifr.ifr_name, ip, dev->mem);
856
857 /* Set "promisc" bit: we want every single packet. */
858 *((u8 *)dev->mem) |= 0x1;
859
860 close(ipfd);
861
862 verbose("device %p: tun net %u.%u.%u.%u\n",
863 (void *)(dev->desc->pfn * getpagesize()),
864 (u8)(ip>>24), (u8)(ip>>16), (u8)(ip>>8), (u8)ip);
865 if (br_name)
866 verbose("attached to bridge: %s\n", br_name);
867 }
868
869 /* Now we know how much memory we have, we copy in device descriptors */
870 statc void map_device_descriptors(struct device_list *devs, unsigned long mem)
871 {
872 struct device *i;
873 unsigned int num;
874 struct lguest_device_desc *descs;
875
876 /* Device descriptor array sits just above top of normal memory */
877 descs = map_zeroed_pages(mem, 1);
878
879 for (i = devs->dev, num = 0; i; i = i->next, num++) {
880 if (num == LGUEST_MAX_DEVICES)
881 errx(1, "too many devices");
882 verbose("Device %i: %s\n", num,
883 i->desc->type == LGUEST_DEVICE_T_NET ? "net"
884 : i->desc->type == LGUEST_DEVICE_T_CONSOLE ? "console"
885 : i->desc->type == LGUEST_DEVICE_T_BLOCK ? "block"
886 : "unknown");
887 descs[num] = *i->desc;
888 free(i->desc);
889 i->desc = &descs[num];
890 }
891 }
892
893 static void __attribute__((noreturn))
894 run_guest(int lguest_fd, struct device_list *device_list)
895 {
896 for (;;) {
897 u32 args[] = { LHREQ_BREAK, 0 };
898 unsigned long arr[2];
899 int readval;
900
901 /* We read from the /dev/lguest device to run the Guest. */
902 readval = read(lguest_fd, arr, sizeof(arr));
903
904 if (readval == sizeof(arr)) {
905 handle_output(lguest_fd, arr[0], arr[1], device_list);
906 continue;
907 } else if (errno == ENOENT) {
908 char reason[1024] = { 0 };
909 read(lguest_fd, reason, sizeof(reason)-1);
910 errx(1, "%s", reason);
911 } else if (errno != EAGAIN)
912 err(1, "Running guest failed");
913 handle_input(lguest_fd, device_list);
914 if (write(lguest_fd, args, sizeof(args)) < 0)
915 err(1, "Resetting break");
916 }
917 }
918
919 static struct option opts[] = {
920 { "verbose", 0, NULL, 'v' },
921 { "sharenet", 1, NULL, 's' },
922 { "tunnet", 1, NULL, 't' },
923 { "block", 1, NULL, 'b' },
924 { "initrd", 1, NULL, 'i' },
925 { NULL },
926 };
927 static void usage(void)
928 {
929 errx(1, "Usage: lguest [--verbose] "
930 "[--sharenet=|--tunnet=(|bridge:)\n"
931 "|--block=|--initrd=]...\n"
932 " vmlinux [args...]");
933 }
934
935 int main(int argc, char *argv[])
936 {
937 unsigned long mem, pgdir, start, page_offset, initrd_size = 0;
938 int c, lguest_fd;
939 struct device_list device_list;
940 void *boot = (void *)0;
941 const char *initrd_name = NULL;
942
943 device_list.max_infd = -1;
944 device_list.dev = NULL;
945 device_list.lastdev = &device_list.dev;
946 FD_ZERO(&device_list.infds);
947
948 while ((c = getopt_long(argc, argv, "v", opts, NULL)) != EOF) {
949 switch (c) {
950 case 'v':
951 verbose = true;
952 break;
953 case 's':
954 setup_net_file(optarg, &device_list);
955 break;
956 case 't':
957 setup_tun_net(optarg, &device_list);
958 break;
959 case 'b':
960 setup_block_file(optarg, &device_list);
961 break;
962 case 'i':
963 initrd_name = optarg;
964 break;
965 default:
966 warnx("Unknown argument %s", argv[optind]);
967 usage();
968 }
969 }
970 if (optind + 2 > argc)
971 usage();
972
973 /* We need a console device */
974 setup_console(&device_list);
975
976 /* First we map /dev/zero over all of guest-physical memory. */
977 mem = atoi(argv[optind]) * 1024 * 1024;
978 map_zeroed_pages(0, mem / getpagesize());
979
980 /* Now we load the kernel */
981 start = load_kernel(open_or_die(argv[optind+1], O_RDONLY),
982 &page_offset);
983
984 /* Write the device descriptors into memory. */
985 map_device_descriptors(&device_list, mem);
986
987 /* Map the initrd image if requested */
     /* 因为在内核中不能做BIOS调用,内存信息由setup通过INT 0X15 来加以查询,
      * 并根据获得的信息生成一张物理内存构成图,称为e820图,再通过参数块传给
      * 内核,使内核知道系统中内存资源的配置.因为在做int 0x15来查询内存构成
      * 是要把调用参数之一设置成xe820,所以叫e820图.
      */

988 if (initrd_name) {
989 initrd_size = load_initrd(initrd_name, mem);
990 *(unsigned long *)(boot+0x218) = mem - initrd_size;
991 *(unsigned long *)(boot+0x21c) = initrd_size;
992 *(unsigned char *)(boot+0x210) = 0xFF;
993 }
994
995 /* Set up the initial linar pagetables. */
996 pgdir = setup_pagetables(mem, initrd_size, page_offset);
997
998 /* E820 memory map: ours is a simple, single region. */
999 *(char*)(boot+E820NR) = 1;
1000 *((struct e820entry *)(boot+E820MAP))
1001 = ((struct e820entry) { 0, mem, E820_RAM });
1002 /* Command line pointer and command line (at 4096) */
1003 *(void **)(boot + 0x228) = boot + 4096;
1004 concat(boot + 4096, argv+optind+2);
1005 /* Paravirt type: 1 == lguest */
1006 *(int *)(boot + 0x23c) = 1;
1007
1008 lguest_fd = tell_kernel(pgdir, start, page_offset);
1009 waker_fd = setup_waker(lguest_fd, &device_list);
1010
1011 run_guest(lguest_fd, &device_list);
1012 }

阅读(2321) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~