/*L:025 This actually initializes a CPU. For the moment, a Guest is only * uniprocessor, so "id" is always 0. */ static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip) { /* We have a limited number the number of CPUs in the lguest struct. */ if (id >= ARRAY_SIZE(cpu->lg->cpus)) return -EINVAL; /* Set up this CPU's id, and pointer back to the lguest struct. */ cpu->id = id; cpu->lg = container_of((cpu - id), struct lguest, cpus[0]); cpu->lg->nr_cpus++; /* Each CPU has a timer it can set. */ init_clockdev(cpu); /* We need a complete page for the Guest registers: they are accessible * to the Guest and we can only grant it access to whole pages. */ cpu->regs_page = get_zeroed_page(GFP_KERNEL); if (!cpu->regs_page) return -ENOMEM; /* We actually put the registers at the bottom of the page. */ cpu->regs = (void *)cpu->regs_page + PAGE_SIZE - sizeof(*cpu->regs); /* Now we initialize the Guest's registers, handing it the start * address. */ lguest_arch_setup_regs(cpu, start_ip); /* Initialize the queue for the Waker to wait on */ init_waitqueue_head(&cpu->break_wq); /* We keep a pointer to the Launcher task (ie. current task) for when * other Guests want to wake this one (eg. console input). */ cpu->tsk = current; /* We need to keep a pointer to the Launcher's memory map, because if * the Launcher dies we need to clean it up. If we don't keep a * reference, it is destroyed before close() is called. */ cpu->mm = get_task_mm(cpu->tsk); /* We remember which CPU's pages this Guest used last, for optimization * when the same Guest runs on the same CPU twice. */ cpu->last_pages = NULL; /* No error == success. */ return 0; }
/*H:030 * Let's jump straight to the the main loop which runs the Guest. * Remember, this is called by the Launcher reading /dev/lguest, and we keep * going around and around until something interesting happens. */ int run_guest(struct lg_cpu *cpu, unsigned long __user *user) { /* We stop running once the Guest is dead. */ while (!cpu->lg->dead) { unsigned int irq; bool more; /* First we run any hypercalls the Guest wants done. */ if (cpu->hcall) { // printk("=== DUMPING REGISTERS HYPERCALL ===\n"); // dump_cpu_regs(cpu); do_hypercalls(cpu); } /* * It's possible the Guest did a NOTIFY hypercall to the * Launcher. */ if (cpu->pending_notify) { /* * Does it just needs to write to a registered * eventfd (ie. the appropriate virtqueue thread)? */ if (!send_notify_to_eventfd(cpu)) { /* OK, we tell the main Launcher. */ if (put_user(cpu->pending_notify, user)) return -EFAULT; return sizeof(cpu->pending_notify); } } /* * All long-lived kernel loops need to check with this horrible * thing called the freezer. If the Host is trying to suspend, * it stops us. */ try_to_freeze(); /* Check for signals */ if (signal_pending(current)) return -ERESTARTSYS; /* * Check if there are any interrupts which can be delivered now: * if so, this sets up the hander to be executed when we next * run the Guest. */ irq = interrupt_pending(cpu, &more); if (irq < LGUEST_IRQS) try_deliver_interrupt(cpu, irq, more); /* * Just make absolutely sure the Guest is still alive. One of * those hypercalls could have been fatal, for example. */ if (cpu->lg->dead) break; /** * If the guest is suspended skip. */ // printk("Checking for suspend\n"); if(cpu->suspended) { // Sleep down_interruptible(&cpu->suspend_lock); // Unlock the lock since we no longer need it up(&cpu->suspend_lock); // set_current_state(TASK_INTERRUPTIBLE); // cond_resched(); // schedule(); // printk("Suspended\n"); // continue; // TODO: Attempt to fix clock skew and nmi here? init_clockdev(cpu); } /* * If the Guest asked to be stopped, we sleep. The Guest's * clock timer will wake us. */ if (cpu->halted) { set_current_state(TASK_INTERRUPTIBLE); /* * Just before we sleep, make sure no interrupt snuck in * which we should be doing. */ if (interrupt_pending(cpu, &more) < LGUEST_IRQS) set_current_state(TASK_RUNNING); else schedule(); continue; } /* * OK, now we're ready to jump into the Guest. First we put up * the "Do Not Disturb" sign: */ local_irq_disable(); /* Actually run the Guest until something happens. */ lguest_arch_run_guest(cpu); /* Now we're ready to be interrupted or moved to other CPUs */ local_irq_enable(); /* Now we deal with whatever happened to the Guest. */ lguest_arch_handle_trap(cpu); } /* Special case: Guest is 'dead' but wants a reboot. */ if (cpu->lg->dead == ERR_PTR(-ERESTART)) return -ERESTART; /* The Guest is dead => "No such file or directory" */ return -ENOENT; }