Help us understand the problem. What is going on with this article?

BitVisorからBIOSを呼び出す

BitVisorからBIOSを呼び出す方法を紹介します。

callrealmode

core/callrealmode.hで定義されている関数群がBIOSを呼び出すためのものです。ここに使いたいものがすでにあれば、簡単です。

なお、仮想マシンを開始した後(ブートセクターを実行後)はBIOSを呼び出してはいけません。

ない場合は追加する必要があります。多少手間ではありますが、他の呼び出しを真似て書けばそれほど難しいものではありません。例として以下のふたつのビデオBIOSの呼び出しを追加します:

  • ボーダーカラーの設定
  • ピクセルの書き込み

core/callrealmode.h

core/callrealmode.hに呼び出したいインターフェイスを追加します。今回グラフィックスモードを使いたいので、モードの定義も増やしておきます:

--- a/core/callrealmode.h
+++ b/core/callrealmode.h
@@ -47,6 +47,7 @@
 #define GETSHIFTFLAGS_INSERT_BIT       0x80

 #define VIDEOMODE_80x25TEXT_16COLORS   0x03
+#define VIDEOMODE_320x200GRAPHICS_16COLORS     0x0D

 struct sysmemmap {
        u64 base;
@@ -92,5 +93,7 @@ void callrealmode_setcursorpos (u8 page_
 void callrealmode_startkernel32 (u32 paramsaddr, u32 startaddr);
 void callrealmode_tcgbios (u32 al, struct tcgbios_args *args);
 void callrealmode_getfontinfo (u8 bh, u16 *es, u16 *bp, u16 *cx, u8 *dl);
+void callrealmode_setbordercolor (int color);
+void callrealmode_writepixel (int page, int color, int x, int y);

 #endif

core/callrealmode.c

core/callrealmode.cではcore/callrealmode.hで定義した関数を実装します。定数や構造体の具体的な定義は後回しにして、とりあえず必要そうなものを書いてみます:

--- a/core/callrealmode.c
+++ b/core/callrealmode.c
@@ -392,5 +392,21 @@ callrealmode_getfontinfo (u8 bh, u16 *es
                *dl = d.u.getfontinfo.dl_ret;
 }

+void callrealmode_setbordercolor (int color) {
+  struct callrealmode_data d;
+  d.func = CALLREALMODE_FUNC_SETBORDERCOLOR;
+  d.u.setbordercolor.color = color;
+  callrealmode_call (&d);
+}
+void callrealmode_writepixel (int page, int color, int x, int y) {
+  struct callrealmode_data d;
+  d.func = CALLREALMODE_FUNC_WRITEPIXEL;
+  d.u.writepixel.page = page;
+  d.u.writepixel.color = color;
+  d.u.writepixel.x = x;
+  d.u.writepixel.y = y;
+  callrealmode_call (&d);
+}
+
 INITFUNC ("global0", callrealmode_init_global);
 INITFUNC ("panic0", callrealmode_panic);

core/callrealmode_asm.h

core/callrealmode_asm.hにはcore/callrealmode.cから使用する定数や構造体の定義を追加します:

--- a/core/callrealmode_asm.h
+++ b/core/callrealmode_asm.h
@@ -49,6 +49,8 @@ enum callrealmode_func {
        CALLREALMODE_FUNC_STARTKERNEL32 = 0x9,
        CALLREALMODE_FUNC_TCGBIOS = 0xA,
        CALLREALMODE_FUNC_GETFONTINFO = 0xB,
+       CALLREALMODE_FUNC_SETBORDERCOLOR = 0xC,
+       CALLREALMODE_FUNC_WRITEPIXEL = 0xD,
 };

 struct callrealmode_printmsg {
@@ -112,6 +114,15 @@ struct callrealmode_getfontinfo {
        u8 dl_ret, bh;
 } __attribute__ ((packed));

+struct callrealmode_setbordercolor {
+       u8 color;
+};
+
+struct callrealmode_writepixel {
+       u8 page, color;
+       u16 x, y;
+} __attribute__ ((packed));
+
 struct callrealmode_data {
        enum callrealmode_func func : 32;
        union {
@@ -126,6 +137,8 @@ struct callrealmode_data {
                struct callrealmode_startkernel32 startkernel32;
                struct callrealmode_tcgbios tcgbios;
                struct callrealmode_getfontinfo getfontinfo;
+               struct callrealmode_setbordercolor setbordercolor;
+               struct callrealmode_writepixel writepixel;
        } u;
 } __attribute__ ((packed));

enum callrealmode_funcに追加した値は次のcore/callrealmode_asm.sに追加するものと一致するようにします。

core/callrealmode_asm.s

core/callrealmode_asm.sはBIOSを呼び出すルーチンです。アセンブリ言語で記述します。Real-address modeへの移行などの処理はすでに書かれているので、新たな部分だけ追加すればOKです。core/callrealmode_asm.hに追加した値とCALLREALMODE_FUNC_*の値が一致していることと、core/callrealmode_asm.hに追加した構造体のメンバーのオフセット+0x30とOFF_*の値が一致していることと、構造体のメンバーにアクセスする際のサイズが一致していることを確認します。

--- a/core/callrealmode_asm.s
+++ b/core/callrealmode_asm.s
@@ -40,6 +40,8 @@
        CALLREALMODE_FUNC_STARTKERNEL32 = 0x9
        CALLREALMODE_FUNC_TCGBIOS = 0xA
        CALLREALMODE_FUNC_GETFONTINFO = 0xB
+       CALLREALMODE_FUNC_SETBORDERCOLOR = 0xC
+       CALLREALMODE_FUNC_WRITEPIXEL = 0xD

        SEG_SEL_CODE_REAL = 0x0000
        SEG_SEL_DATA_REAL = 0x0000
@@ -178,6 +180,11 @@ callrealmode_switch:
        OFF_GETFONTINFO_CX_RET = 0x34
        OFF_GETFONTINFO_DL_RET = 0x36
        OFF_GETFONTINFO_BH = 0x37
+       OFF_SETBORDERCOLOR_COLOR = 0x30
+       OFF_WRITEPIXEL_PAGE = 0x30
+       OFF_WRITEPIXEL_COLOR = 0x31
+       OFF_WRITEPIXEL_X = 0x32
+       OFF_WRITEPIXEL_Y = 0x34

        # Which function?
        mov     OFF_FUNC(%bp),%ax
@@ -205,6 +212,10 @@ callrealmode_switch:
        je      tcgbios
        cmp     $CALLREALMODE_FUNC_GETFONTINFO,%ax
        je      getfontinfo
+       cmp     $CALLREALMODE_FUNC_SETBORDERCOLOR,%ax
+       je      setbordercolor
+       cmp     $CALLREALMODE_FUNC_WRITEPIXEL,%ax
+       je      writepixel
        # Error!
        cld
        mov     $(errormsg_data-1-callrealmode_start+CALLREALMODE_OFFSET),%di
@@ -447,6 +458,25 @@ getfontinfo:
        mov     %dl,OFF_GETFONTINFO_DL_RET(%bp)
        ret

+# setbordercolor
+#
+setbordercolor:
+       mov     OFF_SETBORDERCOLOR_COLOR(%bp),%bh
+       mov     $0x1001,%ax
+       int     $0x10
+       ret
+
+# writepixel
+#
+writepixel:
+       mov     OFF_WRITEPIXEL_PAGE(%bp),%bh
+       mov     OFF_WRITEPIXEL_COLOR(%bp),%al
+       mov     OFF_WRITEPIXEL_X(%bp),%cx
+       mov     OFF_WRITEPIXEL_Y(%bp),%dx
+       mov     $0x0C,%ah
+       int     $0x10
+       ret
+
 # Subroutines
 #
 paging_and_protection_off:

機能テスト

上で追加した機能をテストしてみます。今回はcore/main.cから呼び出してみることにします。

diff --git a/core/main.c b/core/main.c
--- a/core/main.c
+++ b/core/main.c
@@ -322,6 +322,29 @@ process_cpu_type_ext (void)
        }
 }

+static void drawtest (void) {
+  int x,y,x2,y2,xp2,x12,d;
+  callrealmode_setvideomode (VIDEOMODE_320x200GRAPHICS_16COLORS);
+  callrealmode_setbordercolor (3);
+  for(y=0;y<200;y+=2)for(x=y%4;x<320;x+=4)callrealmode_writepixel(0,7,x,y);
+  for(y=50;y<150;y++)for(x=85;x<235;x++)callrealmode_writepixel(0,15,x,y);
+  x=30,y=0,x2=900,y2=0;
+  while(x>=y){
+    for(int i=0;i<x;i++)callrealmode_writepixel(0,4,160+i,100+y),
+                         callrealmode_writepixel(0,4,160-i,100+y),
+                         callrealmode_writepixel(0,4,160+i,100-y),
+                         callrealmode_writepixel(0,4,160-i,100-y),
+                         callrealmode_writepixel(0,4,160+y,100+i),
+                         callrealmode_writepixel(0,4,160-y,100+i),
+                         callrealmode_writepixel(0,4,160+y,100-i),
+                         callrealmode_writepixel(0,4,160-y,100-i);
+    y2+=y+y+1,y++,xp2=900-y2,x12=x2-x-x+1;
+    if(xp2-x12<x2-xp2)x--,x2=x12;
+  }
+  if((d=msgopen("ttyin"))>=0)msgsendint(d,0),msgclose(d);
+  callrealmode_setvideomode (VIDEOMODE_80x25TEXT_16COLORS);
+}
+
 static void
 bsp_init_thread (void *args)
 {
@@ -356,6 +379,7 @@ bsp_init_thread (void *args)
        } else if (!uefi_booted) {
                load_drivers ();
                get_tmpbuf (&tmpbufaddr, &tmpbufsize);
+               drawtest ();
                load_bootsector (bios_boot_drive, tmpbufaddr, tmpbufsize);
                sync_cursor_pos ();
        }

ブートセクターの読み込みの前に、グラフィックスモードに切り替え、ボーダーカラーを設定し、背景に点を並べ、白い長方形と赤い円を描き、キー入力を待つだけの簡単なプログラムです。実行すると以下のようになります:

a.jpeg

完璧だ...!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした