Kernel110615: bioscall.S注记
Email: zcatt@163.com
Blog http://zcatt.blog.chinaunix.net
声明
仅限学习交流,禁止商业用途。转载需注明出处。
版本记录
Date Ver Note
2011-06-15 0.1 Draft. zcatt, Beijing
kernel/arch/x86/boot/bioscall.S实现了c函数intcall(), 原型如下,
void intcall(u8 int_no, const struct biosregs *ireg, struct biosregs *oreg);
其中biosregs计44bytes.
struct biosregs {
union {
struct {
u32 edi;
u32 esi;
u32 ebp;
u32 _esp;
u32 ebx;
u32 edx;
u32 ecx;
u32 eax;
u32 _fsgs;
u32 _dses;
u32 eflags;
};
struct {
u16 di, hdi;
u16 si, hsi;
u16 bp, hbp;
u16 _sp, _hsp;
u16 bx, hbx;
u16 dx, hdx;
u16 cx, hcx;
u16 ax, hax;
u16 gs, fs;
u16 es, ds;
u16 flags, hflags;
};
struct {
u8 dil, dih, edi2, edi3;
u8 sil, sih, esi2, esi3;
u8 bpl, bph, ebp2, ebp3;
u8 _spl, _sph, _esp2, _esp3;
u8 bl, bh, ebx2, ebx3;
u8 dl, dh, edx2, edx3;
u8 cl, ch, ecx2, ecx3;
u8 al, ah, eax2, eax3;
};
};
};
c调用intcall()时, eax, edx和ecx分别容纳int_no, ireg, 和oreg.
bioscall.S的详细注释如下,
/* -----------------------------------------------------------------------
*
* Copyright 2009 Intel Corporation; author H. Peter Anvin
*
* This file is part of the Linux kernel, and is made available under
* the terms of the GNU General Public License version 2 or (at your
* option) any later version; incorporated herein by reference.
*
* ----------------------------------------------------------------------- */
/*
* "Glove box" for BIOS calls. Avoids the constant problems with BIOSes
* touching registers they shouldn't be.
*/
/*zcatt, 原型, void intcall(byte int_no -- %eax), biosregs *ireg -- %edx, biosregs *oreg -- %ecx) */
.code16gcc
.text
.globl intcall
.type intcall, @function /*zcatt, intcall是function */
intcall:
/* Self-modify the INT instruction. Ugly, but works. */
cmpb %al, 3f /*zcatt, %al是int_no */
je 1f /*zcatt, if already set, pass */
movb %al, 3f /*zcatt, int_no写道下面的中断指令参数中 */
jmp 1f /* Synchronize pipeline */ /*zcatt, 这个很重要 */
1:
/* Save state */ /*zcatt, 保存现场, 函数退出时复原 */
pushfl /*zcatt, push %eflag, 4byte */
pushw %fs /*zcatt, push %fs, 2byte */
pushw %gs /*zcatt, push %gs, 2byte */
pushal /*zcatt, push %eax, %ecx, %edx, %ebx, %esp, %ebp, %esi, %edi, 计4byte*8 */
/*zcatt, 至此, 栈的内容从高到底是, 其中eip是caller的call语句压入的: ip, eflag, fsgs, eax, ecx, edx, ebx, esp, ebp, esi, edi */
/* Copy input state to stack frame */
subw $44, %sp /*zcatt, 分配栈空间, 容纳ireg */
movw %dx, %si /*zcatt, %dx是intcall()的入口参数ireg */
movw %sp, %di
movw $11, %cx
rep; movsd /*zcatt, caller的ireg内容写入栈[%sp, $44(%sp)] */
/* Pop full state from the stack */ /*zcatt, 栈内的ireg内容装入到各自寄存器中 */
popal
popw %gs
popw %fs
popw %es
popw %ds
popfl
/* Actual INT */
.byte 0xcd /* INT opcode */ /*zcatt, 原始的办法, 凑intr指令 */
3: .byte 0 /*zcatt, intNo已经在之前设置好 */
/* Push full state to the stack */ /*zcatt, intr后的结果按照oreg的格式保存到栈中 */
pushfl
pushw %ds
pushw %es
pushw %fs
pushw %gs
pushal
/* Re-establish C environment invariants */ /*zcatt, intcall的调用者应当是c程序, */
cld
movzwl %sp, %esp
movw %cs, %ax
movw %ax, %ds
movw %ax, %es
/* Copy output state from stack frame */
movw 68(%esp), %di /* Original %cx == 3rd argument */ /*zcatt,
ecx是oreg的地址, 现在的栈情况: eip, eflag, fsgs, eax, ECX, edx, ebx, esp, ebp,
esi, edi, oreg的内容(44bytes). 到cx的距离合计44+4byte*8=68bytes */
andw %di, %di
jz 4f
movw %sp, %si
movw $11, %cx
rep; movsd /*zcatt, 栈中的oreg内容写入到caller的oreg地址 */
4: addw $44, %sp /*zcatt, 退出栈中的oreg内容 */
/* Restore state and return */ /*zcatt, 退出前复原 */
popal
popw %gs
popw %fs
popfl
retl
.size intcall, .-intcall /*zcatt, 设定intcall函数的大小 */
阅读(1526) | 评论(2) | 转发(0) |