Mondo IT

recensioni, articoli e approfondimenti sul mondo IT

Posts Tagged ‘C

[EN] dig a hole in QEMU: how to execute code on the host from VMs (Part 1)

leave a comment »

In the next posts I’ll show you my recent works on QEMU. The purpose of my work is execute code on the Host machine every time that a virtual machine write or read to certain memory address. As you may know, QEMU is not largely documented, so in these posts I try to simplify works for people who are interested in these kind of operation.

The design of the solution that I’ve implemented starts from a QEMU emulated device, called LittleP. In addiction, we need of a Guest drivers that is programmed to write/read data to a fixed memory address. In my case I have used a GNU/Linux virtual machine, but probably it is possible to do the same thing with others operating systems.

So let’s start with the addiction of a new QEMU emulated device. To do this we have to add a new file (in this example littlep.c) in qemu/hw directory. This file should be something like this:

Leggi il seguito di questo post »

Annunci

Written by Michele Paolino

13/11/2012 at 12:37

Uno scheduler per XEN

leave a comment »

questo è uno scheduler (random) per XEN. Il suo valore è semplicemente accademico senza alcuna applicazione pratica.

This is a random scheduler for XEN. I wrote this scheduler for academic purposes only.

/****************************************************************************
 * (C) 2010 - Michele Paolino
 ****************************************************************************
 *
 *        File: common/sched_random.c
 *      Author: Michele Paolino
 *
 *      Description: Random CPU scheduler
 */

#include <xen/lib.h>
#include <xen/sched.h>
#include <xen/time.h>
#include <xen/sched-if.h>
#include <xen/softirq.h>
#include <xen/errno.h>
#include <xen/list.h>
#include <xen/timer.h>
#include <xen/randmd5.h>

int tot_vcpu=0;
MD5_CTX mdContext;

#define RAND_PCPU(_c)     ((struct random_pcpu *)per_cpu(schedule_data, _c).sched_priv)
#define RAND_VCPU(_vcpu)  ((struct random_vcpu *) (_vcpu)->sched_priv)
#define RUNQ(_cpu)        (&(RAND_PCPU(_cpu)->runq))

struct random_pcpu {
 struct list_head runq;
};

struct random_vcpu{
 struct list_head runq_elem;
 struct vcpu *vcpu;
};

static inline void __runq_tickle(unsigned int cpu, struct random_vcpu *new)
{
 struct random_vcpu * const cur = RAND_VCPU(per_cpu(schedule_data, cpu).curr);
 cpumask_t mask;

 ASSERT(cur);
 cpus_clear(mask);
 printk("\nTickle vcpu %d\n", cur->vcpu->vcpu_id);

 if ( vcpu_runnable(cur->vcpu) )
 {
 cpu_set(cpu, mask);
 printk("\nI'm setting the mask for the current vcpu\n");
 }
 /* Send scheduler interrupts to designated CPUs */
 if ( !cpus_empty(mask) ){
 printk("\nRaising softirq\n");
 cpumask_raise_softirq(mask, SCHEDULE_SOFTIRQ);
 }
}

static inline int  __vcpu_on_runq(struct random_vcpu *svc)
{
 return !list_empty(&svc->runq_elem);
}

static inline void __runq_insert(unsigned int cpu, struct random_vcpu *svc)
{
 struct list_head *runq = RUNQ(cpu);
 BUG_ON( cpu != svc->vcpu->processor );
 if (!__vcpu_on_runq(svc)) list_add(&svc->runq_elem,runq);
 return;
}

static inline void __runq_remove(struct random_vcpu *svc)
{
 BUG_ON( !__vcpu_on_runq(svc) );
 list_del_init(&svc->runq_elem);
}

static inline void __random_vcpu_check(struct vcpu *vc)
{
 struct random_vcpu * const svc = RAND_VCPU(vc);
 BUG_ON( (svc->vcpu) != vc );
}

static int random_pcpu_init(int cpu)
{
 struct random_pcpu *spc;

 /* Allocate per-PCPU info */

 spc = xmalloc(struct random_pcpu);
 if ( spc == NULL )
 return -1;
 memset(spc, 0, sizeof(*spc));

 INIT_LIST_HEAD(&spc->runq);
 per_cpu(schedule_data, cpu).sched_priv = spc;
 return 0;
}

static int random_vcpu_init(struct vcpu *vc){
 struct random_vcpu *svc;

 svc = xmalloc(struct random_vcpu);
 if ( svc == NULL )
 return -1;
 memset(svc, 0, sizeof(*svc));

 INIT_LIST_HEAD(&svc->runq_elem);

 svc->vcpu = vc;
 vc->sched_priv = svc;

 /* Allocate per-PCPU info */
 if ( unlikely(!RAND_PCPU(vc->processor)) )
 {
 if ( random_pcpu_init(vc->processor) != 0 )
 return -1;
 }
 __random_vcpu_check(vc);

 tot_vcpu++;
 printk("\nadd VCPU %d tot_vcpu=%d\n", vc->vcpu_id, tot_vcpu);
 return 0;
}

static void random_vcpu_destroy(struct vcpu *vc)
{
 struct random_vcpu * const svc = RAND_VCPU(vc);
 printk("\n\nDestroying vcpu %d\n\n",vc->vcpu_id);
 tot_vcpu--;
 BUG_ON( !list_empty(&svc->runq_elem) );
 list_del(&svc->runq_elem);
 xfree(svc);
}

struct task_slice random_schedule(s_time_t now){
 const unsigned int cpu = smp_processor_id();
 struct list_head * runq = RUNQ(cpu);
 struct random_vcpu * const scurr = RAND_VCPU(current);
 struct random_vcpu *snext;
 struct task_slice ret;
 int next_vcpu=0;

 next_vcpu = (MD5Final (&mdContext)) % tot_vcpu;
 __random_vcpu_check(current);

 if ( vcpu_runnable(current) )
 __runq_insert(cpu, scurr);
 else
 BUG_ON( is_idle_vcpu(current) || list_empty(runq) );

 while (next_vcpu!=0){
 next_vcpu--;
 list_move(runq, runq->next);
 }

 snext = list_entry(runq->next, struct random_vcpu, runq_elem);
 __runq_remove(snext);

 ret.time = MILLISECS(10);
 ret.task=snext->vcpu;    
 __random_vcpu_check(current);
 return ret;
}

static void __random_init(void){
 unsigned char digest[16];
 int i;
 long unsigned int mask= 0xFF;
 long unsigned int string_now = NOW();
 MD5Init (&mdContext);
 for (i=0;i<8;i++){
 digest[i]=(char) ((string_now & mask) >> 8*i);
 mask <<=8;
 }
 MD5Update (&mdContext, (unsigned char*)digest, sizeof(s_time_t));
}

static void random_vcpu_wake( struct vcpu *vc){
 struct random_vcpu * const svc = RAND_VCPU(vc);
 const unsigned int cpu = vc->processor;
 BUG_ON ( is_idle_vcpu(vc) );

 /* Put the VCPU on the runq and tickle CPUs */
 __runq_insert(cpu, svc); //inserisco in coda
 __runq_tickle(cpu, svc);  // raise softirq   

 return;
}

static void random_vcpu_sleep(struct vcpu *vc)
{
 struct random_vcpu * const svc = RAND_VCPU(vc);
 printk("Sleeping..\n");
 BUG_ON( is_idle_vcpu(vc) );
 if ( per_cpu(schedule_data, vc->processor).curr == vc )
 cpu_raise_softirq(vc->processor, SCHEDULE_SOFTIRQ);
 else if ( __vcpu_on_runq(svc) )
 __runq_remove(svc);
}

static void random_init(void)
{
 tot_vcpu=0;
 __random_init();
}

struct scheduler sched_rand_def = {
 .name           = "Random Scheduler",
 .opt_name       = "random",
 .sched_id       = 17,
 .init_vcpu      = random_vcpu_init,
 .wake           = random_vcpu_wake,
 .sleep          = random_vcpu_sleep,
 .destroy_vcpu   = random_vcpu_destroy,
 .do_schedule    = random_schedule,
 .init           = random_init,
};

Written by Michele Paolino

21/05/2010 at 22:16

XEN: Gli scheduler SEDF e Credit

with 2 comments

Come funzionano gli scheduler tuttora utilizzati dal sistema di virtualizzazione XEN? Lo spiegheremo in questo articolo.

Sono due gli scheduler presenti e utilizzabili in questo momento nell’hypervisor di XEN, entrambi in grado di lavorare in work conserving mode. La work conserving mode è la capacità di uno scheduler di dare a un dominio, in alcune condizioni, l’intera CPU.

Credit scheduler è quello utilizzato di default dall’hypervisor, è il più giovane e ancora in fase di sviluppo. SEDF invece non è più sviluppato ma viene ancora rilasciato perché più stabile per alcune specifiche applicazioni. A livello algoritmico i due scheduler differiscono per i criteri con cui ordinano una coda di VCPU eseguibili. Queste code sono pari alla quantità di processori fisici presenti nel sistema. A ogni dominio può essere assegnata più di una CPU virtuale.

SEDF scheduler

Simple Earliest Deadline First (SEDF) è molto semplice e basa il suo funzionamento su tre variabili, p (period), s(slice) e x(extra time). L’algoritmo prevede che una macchina virtuale deve avere accesso alla CPU per s millisecondi ogni p millisecondi. Il valore x invece è un flag che determina se al dominio è permesso tempo-CPU extra utile per abilitare il work conserving mode. Questi valori sono configurabili dominio per dominio.

SEDF mantiene per ogni VCPU il tempo rimasto prima della scadenza del periodo (deadline), e la somma dei tempi processore che ancora spettano al dominio prima dello scadere del periodo. I processori virtuali sono ordinati in una coda in base alla deadline più vicina. Quando le VCPU vengono schedulate, la loro deadline si sposta avanti nel tempo. Nel caso in cui lo slice di una macchina non permette di realizzare il rapporto p/s delle altre, esso viene ridotto.

SEDF manca del supporto al load balancing su sistemi multiprocessore e valuta le statistiche di utilizzo del processore fisico per VCPU.

Credit scheduler

Credit scheduler è usato dalle più recenti versioni di XEN come scheduler di default. Ogni dominio ha due variabili associate ad esso, un peso (weight) e un limite (cap). Il peso rappresenta la quantità di CPU disponibile per il dominio in ogni unità di tempo, il limite invece ne stabilisce il massimo. Esso è un valore assoluto che descrive la percentuale di CPU di cui può usufruire il dominio. I pesi invece sono gli uni relativi agli altri. Dare a tutte le macchine virtuali un peso uguale, di qualunque valore esso sia, comporta gli stessi effetti su tutti i domini.

Ogni CPU gestisce una lista ordinata di VCPU eseguibili. La priorità è settata su due valori: under e over. Questi valori indicano se le VCPU hanno superato o meno il tempo d’uso che spettava loro del processore fisico nel periodo corrente. Quando viene inserita una VCPU in coda viene posta dopo tutte le altre di uguale priorità.

Ogni volta che una CPU virtuale viene messa in esecuzione, consuma alcuni dei suoi crediti. Se il conto dei crediti consumati è negativo, la priorità della VCPU viene impostata a over.

Quando la somma dei crediti di tutti i domini è negativa, vengono assegnati nuovi crediti a tutti i domini. Ogni volta che la funzione di scheduling do_schedule deve decidere quale VCPU schedulare, preleva semplicemente l’elemento che è in testa alla coda.

Prima di andare in idle un processore fisico verifica che non ci siano VCPU eseguibili. Inoltre quando un processore non trova VCPU che sono under nella sua coda va a cercarla nella coda di altri eventuali processori. Questo comportamento garantisce load balancing su sistemi multiprocessore.

A differenza di SEDF, Credit valuta le statistiche di utilizzo del processore fisico per dominio.

Written by Michele Paolino

29/03/2010 at 21:35

XEN: come viene descritto un dominio

leave a comment »

Un dominio nel sistema di virtualizzazione XEN è una entità che incapsula al suo interno un ambiente completo per l’esecuzione di un sistema operativo ospite.

Nella struttura domain sono contenute tutte le informazioni relative al dominio e alle risorse ad esso allocate. Questa viene definita nel file sched.h contenuto nella cartella xen/include/xen/. Attraverso tale struttura, quindi, ogni macchina virtuale in esecuzione viene gestita e rappresentata.

Ne verrà discussa ora la parte più significativa :

struct domain

{

domid_t domain_id;

spinlock_t page_alloc_lock; /* protects all the following fields */

struct page_list_head page_list; /* linked list, of size tot_pages */

struct page_list_head xenpage_list; /* linked list (size xenheap_pages) */

unsigned int tot_pages; /* number of pages currently possesed */

unsigned int max_pages; /* maximum value for tot_pages */

unsigned int xenheap_pages; /* # pages allocated from Xen heap */

/* Scheduling. */

void *sched_priv; /* scheduler-specific data */

struct domain *next_in_list;

struct domain *next_in_hashbucket;

struct list_head rangesets;

spinlock_t rangesets_lock;

struct vcpu *vcpu[MAX_VIRT_CPUS];

shared_info_t *shared_info; /* shared data area */

/* Event channel information. */

struct evtchn *evtchn[NR_EVTCHN_BUCKETS];

spinlock_t event_lock;

struct grant_table *grant_table;

};

Come è facile immaginare, ogni dominio è caratterizzato da un identificatore rappresentato dalla variabile domain_id. All’interno della struttura vengono anche memorizzate tutte le informazioni riguardanti le pagine di memoria dedicate alla macchina ospite. In particolare, le variabili tot_pages e max_pages descrivono il numero massimo e quello attuale di pagine di memoria fruibili dal dominio.

Per quanto riguarda lo scheduling ogni dominio conserva un puntatore a void di nome sched_priv utile agli sviluppatori dello scheduler per allocare a quell’indirizzo dati utili al corretto svolgimento delle funzioni di scheduling. L’ultima variabile presente nella sezione scheduling è un array di CPU virtuali (VCPU). Ogni CPU virtuale è una astrazione del processore fisico della macchina.

La variabile shared_info contiene informazioni aggiornate dinamicamente run-time. Essa è utilizzata dalla macchina virtuale per reperire informazioni sullo stato globale del sistema, quali ad esempio le VCPU del dominio in stato runnable, gli event channel disponibili, il tempo di sistema e alcune informazioni relative all’architettura.

Infine viene descritta la sezione riguardante gli event channel. Questi sono un meccanismo per notifiche asincrone all’interno di XEN. Assieme alle shared memory pages, gli event channel vengono utilizzati per comunicazioni tra back-end e front-end di device driver o di applicazioni come XenStore.

Il codice contenuto nelle parti non commentate consiste in flag che descrivono caratteristiche della macchina virtuale come ad esempio il fatto se una macchina è paravirtualizzata o meno.

Written by Michele Paolino

24/03/2010 at 23:53

memorylocker.c

leave a comment »

Questo programmino scritto in C mi è utile per occupare RAM per rendere confrontabili per dei benchmark una macchina reale e una macchina virtuale.

#include <sys/mman.h>
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
void freemem(int signalValue);
char* memory;
int main(int argc, char** argv){
signal(SIGINT,freemem);
int n=atoi(argv[1]);
printf("\nalloco %dMB di RAM\n",n);
const int alloc_size = n * 1024 * 1024;
memory = malloc(alloc_size);
mlock(memory, alloc_size);
size_t i;
size_t page_size = getpagesize();
for(i=0; i<alloc_size; i+= page_size)
memory[i]=0;
pause();
}
void freemem(int signalValue){
printf("\nricevuto segnale di chiusura, libero la memoria ed esco\n");
free(memory);
exit(0);
}

Written by Michele Paolino

20/07/2009 at 10:52

Pubblicato su GNU/linux, programmazione

Tagged with , ,