2022 虎符 pwn hfdev(二)

承接上文
https://blog.csdn.net/yongbaoii/article/details/123789460

BH

那么我们现在就理解了BH在整个qemu中的地位。

说白了就是可以通过bh,能让qemu的poll机制产生回调。

这种中断并不是在qemu中被提出的,是在linux里面就有的。

在一些linux的书籍文献中这样介绍:

中断句柄只是中断处理的第一部分,因为下面一些限制,必须要有另外一部分来完整的处理中断:
1.中断句柄是异步运行的,只要发生中断就会进入中断句柄,而中断的发生是异步的,也就是说随时可以发生。因此中断句柄可能会中断一些正在执行的重要代码,包括另外一个中断句柄。
2.中断句柄运行时需要关中断,最好情况是禁止了当前的中断级(未设置SA_INTERRUPT),最坏的情况是所有的中断被中断(设置SA_INTERRUPT)。当然,关中断只是运行中断句柄时必要的步骤,适当的时候还是需要打开的。同样这也决定了中断句柄要尽快结束。
3.中断句柄一般都是时间紧迫的任务,因为他们处理的是硬件。
4.中断句柄不运行在进程上下文,因此不能被堵塞。
因此,中断处理分成了两部分,第一部分就是中断句柄(top halves),一旦发生中断就必须执行;第二部分叫做bottom halves,用来处理剩下的那些不那么紧急的工作,目的很简单,就是让中断句柄尽可能快的返回。

那么我们再来详细看一下qemu中的BH

BH 数据结构

struct QEMUBH {
    AioContext *ctx;	// 下半部所在的context
    QEMUBHFunc *cb;		// 下半部要执行的函数
    void *opaque;		// 函数参数
    QEMUBH *next;		// 下一个要执行的下半部
    bool scheduled;		// 使能bh,是否被调度,true:下一次dispatch会触发cb; false:下一次dispatch不会触发cb
    bool idle; 
    bool deleted;		// 标记是否将bh删除
};

BH数据结构的最后三个属性用于控制事件循环线程对BH的操作行为。
为什么要有这三个属性?因为bh的注册和执行是异步地,因此需要有一种方法提供给注册者用来通知执行者,注册者期望bh被怎样执行。
scheduled用来通知执行者,期望在下一次dispatch时bh被调度到;idle用于通知执行者bh不用作progress计数;deleted通知执行者bh被调度一次之后就删除。

qemu主线程有默认的事件循环qemu_aio_context,bh挂载到主线程的事件循环有接口qemu_bh_new可以直接调用

/* Functions to operate on the main QEMU AioContext.  */
QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
{   
    return aio_bh_new(qemu_aio_context, cb, opaque);
}

bh还有一种用法是只执行一次,然后就删除bh,这个通过aio_bh_schedule_oneshot接口可以实现
而普通bh执行方式是调用qemu_bh_schedule,虽然也只调度一次但不会被删除,下一次调度不需要重新注册

事件循环在poll到fd准备好之后,会调度qemu定制的回调函数aio_ctx_dispatch,其主要功能是执行fd对应的回调函数,但在此之前会先检查context上是否挂载有bh,如果有先执行bh。

/* 注册到AioContext的回调函数,当fd准备好之后,事件循环机制会调度这个回调 */
static void
aio_dispatch(AioContext *ctx)
{
    qemu_lockcnt_inc(&ctx->list_lock);
    aio_bh_poll(ctx);
    aio_dispatch_handlers(ctx);
    qemu_lockcnt_dec(&ctx->list_lock);
}

static gboolean
aio_ctx_dispatch(GSource     *source,
                 GSourceFunc  callback,
                 gpointer     user_data)
{
#ifdef DEBUG
    g_print("%s\n", __FUNCTION__);
#endif
    AioContext *ctx = (AioContext *) source;

    aio_dispatch(ctx);
    return TRUE;
}

qemu时钟系统

qemu支持四种时钟

QEMU_CLOCK_REALTIME 不受虚拟系统的影响,随时间流逝而累加计数
QEMU_CLOCK_VIRTUAL 虚拟时钟,记录虚拟系统的时间滴答
QEMU_CLOCK_HOST 这个类似墙上时钟,修改宿主机系统时间会改变这个时间
QEMU_CLOCK_VIRTUAL_RT 在非icount模式下和QEMU_CLOCK_VIRTUAL,在icount模式下于QEMU_CLOCK_VIRTUAL不同的是在虚拟cpu休眠的时候该值也会累加

四个时钟使用类型作为索引放在qemu_clocks数组中,描述时钟的数据结构为QEMUClock。
QEMUClock数据结构如下

typedef struct QEMUClock {
    /* We rely on BQL to protect the timerlists */
    QLIST_HEAD(, QEMUTimerList) timerlists;

    NotifierList reset_notifiers;
    int64_t last;

    QEMUClockType type;
    bool enabled;
} QEMUClock;

QEMUTimerList用于存放定时器链表

timerlist_new函数用于初始化时钟的定时器链表

QEMUTimerList *timerlist_new(QEMUClockType type,
                             QEMUTimerListNotifyCB *cb,
                             void *opaque)
{
    QEMUTimerList *timer_list;
    QEMUClock *clock = qemu_clock_ptr(type);

    timer_list = g_malloc0(sizeof(QEMUTimerList));
    qemu_event_init(&timer_list->timers_done_ev, true);
    timer_list->clock = clock;
    timer_list->notify_cb = cb;
    timer_list->notify_opaque = opaque;
    qemu_mutex_init(&timer_list->active_timers_lock);
    QLIST_INSERT_HEAD(&clock->timerlists, timer_list, list);
    return timer_list;
}

这个函数其实就是把一个定时器回调函数注册到了这个时钟的timer队列里面
主线程的定时器不当可以从定时器结构QEMUClock.timer_list 中索引,还可以从main_loop_tlg中索引。

再介绍一个timer_init_full函数
这是源码

void timer_init_full(QEMUTimer *ts,
                     QEMUTimerListGroup *timer_list_group, QEMUClockType type,
                     int scale, int attributes,
                     QEMUTimerCB *cb, void *opaque);

/**
 * timer_init:
 * @ts: the timer to be initialised
 * @type: the clock to associate with the timer
 * @scale: the scale value for the timer
 * @cb: the callback to call when the timer expires
 * @opaque: the opaque pointer to pass to the callback
 *
 * Initialize a timer with the given scale on the default timer list
 * associated with the clock.
 * See timer_init_full for details.
 */

看注释就能明白
这个函数对QEMUTimer结构体进行了设置。
设置它所在了timerlist
设置时间
设置回调函数等等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值