当前位置: 首页 > 工具软件 > Lguest > 使用案例 >

HTML虚拟机源码,Lguest 虚拟机源代码分析:launcher (代码详解) (下)

赫连睿
2023-12-01

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 }

 类似资料: