* OSをもっと小さくしよう!(その2)
 -(by [[K]], 2006.09.29)
 -発展課題のページ(全部読む前にここを読むのは混乱するのでおすすめじゃないです)
 *** はじめに
 -[[advance/smaller1]]で10KB近いダイエットに成功した haribote.sys ですが、やっぱり.bhsと比べると明らかに見劣りします。[[advance/smaller1]]を適用した bootpack.hrb を圧縮すると16,372バイト、つまりさらに13KBも小さくなるというわけです。うーん、どうにかしてこのサイズに近づけたいです。
 -ということで、起動時に自己展開する haribote.sys を作ろうと思います。・・・そんなのすごくむずかしいよと思うかもしれませんが、そんなことはありません。
 *** 改造内容
 -改造としていますが、実は短いので作り直しました(展開に不要な部分を削っていくとこれしか残らないので)。アルゴリズムは、img_bhs[]内に圧縮されたharibote.bhsファイルの中身を詰め込んでおいて、それをtek_decomp()で展開したあとに、osselectしているだけです。割り込みを許可してもやることがないので(キー入力があっても読み捨てるくらいしかできないし)、割り込みは禁止したままにしました。起動時間が長くなるのが嫌だったので、メモリテストはしていません(どうせharibote.bhsがメモリテストするわけですしね)。16MB以上のメモリを勝手に仮定しています。まあ問題はないでしょう。
 -改造としていますが、実は短いので作り直しました(展開に不要な部分を削っていくとこれしか残らないので)。アルゴリズムは、img_bhs[]内に圧縮されたharibote.bhsファイルの中身を詰め込んでおいて、それをtek_decomp()で展開したあとに、osselectしているだけです。割り込みを許可してもやることがないので(キー入力があっても読み捨てるくらいしかできないし)、割り込みは禁止したままにしました。起動時間が長くなるのが嫌だったので、メモリテストはしていません(どうせharibote.bhsがメモリテストするわけですしね)。とりあえず16MBのメモリはあるだろうと勝手に仮定しています。まあ問題はないでしょう。
 ----
 -bootpack.h
  
  /* naskfunc.nas */
  void load_gdtr(int limit, int addr);
  void farjmp(int eip, int cs);
  void asm_osselect_third(int esp);
  
  /* tek.c */
  int tek_getsize(unsigned char *p);
  int tek_decomp(unsigned char *p, char *q, int size);
  
  /* bootpack.c */
  #define MEMMAN_FREES       4090       /* これで約32KB */
  #define MEMMAN_ADDR        0x003c0000
  struct SEGMENT_DESCRIPTOR {
      short limit_low, base_low;
      char base_mid, access_right;
      char limit_high, base_high;
  };
  struct FREEINFO {      /* あき情報 */
      unsigned int addr, size;
  };
  struct MEMMAN {        /* メモリ管理 */
      int frees, maxfrees, lostsize, losts;
      struct FREEINFO free[MEMMAN_FREES];
  };
  void osselect(char *bhs, int *tmp);
  void osselect_second(void);
  void init_gdt(void);
  void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar);
  #define ADR_GDT        0x00270000
  #define LIMIT_GDT      0x0000ffff
  #define ADR_BOTPAK     0x00280000
  #define LIMIT_BOTPAK   0x0007ffff
  #define AR_DATA32_RW   0x4092
  #define AR_CODE32_ER   0x409a
  void memman_init(struct MEMMAN *man);
  unsigned int memman_alloc(struct MEMMAN *man, unsigned int size);
  int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size);
  unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size);
  int memman_free_4k(struct MEMMAN *man, unsigned int addr, unsigned int size);
  
  /* tek.c */
  int tek_getsize(unsigned char *p);
  int tek_decomp(unsigned char *p, char *q, int size);
  
 ----
 -naskfunc.nas
  
  [FORMAT "WCOFF"]
  [INSTRSET "i486p"]
  [BITS 32]
  [FILE "naskfunc.nas"]
  
          GLOBAL  _load_gdtr, _farjmp, _asm_osselect_third
  
  [SECTION .text]
  
  _load_gdtr:     ; void load_gdtr(int limit, int addr);
          MOV     AX,[ESP+4]
          MOV     [ESP+6],AX
          LGDT    [ESP+6]
          RET
  
  _farjmp:        ; void farjmp(int eip, int cs);
          JMP FAR [ESP+4]
          RET
  
  _asm_osselect_third:
          MOV     AX,SS
          MOV     FS,AX
          MOV     GS,AX
          MOV     ESP,[ESP+4]
          JMP     2*8:0x0000001b
  
 ----
 -bootpack.c
  
  #include "bootpack.h"
  
  extern char img_bhs[100 * 1024]; /* サイズはてきとう */
  
  void HariMain(void)
  {
      struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
      int size = tek_getsize(img_bhs);
      char *decomp = img_bhs;
      init_gdt();
      memman_init(memman);
      memman_free(memman, 0x00001000, 0x0009e000); /* 0x00001000 - 0x0009efff */
      memman_free(memman, 0x00400000, 0x00c00000); /* とりあえず16MBくらいはあるかなということで */
      if (size > 0) {
          decomp = (char *) memman_alloc_4k(memman, size);
          tek_decomp(img_bhs, decomp, size);
      }
      osselect(decomp, (int *) memman_alloc_4k(memman, 512 * 1024));
  }
  
  void osselect(char *bhs, int *tmp)
  {
      struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;
      int i, *bootpack = (int *) ADR_BOTPAK;
      for (i = 0; i < (LIMIT_BOTPAK + 1) / 4; i++) {
          tmp[i] = bootpack[i];
      }
      set_segmdesc(gdt + 8191, LIMIT_BOTPAK, (int) tmp, AR_CODE32_ER);
      *((int *) ADR_BOTPAK) = (int) bhs;
      farjmp((int) osselect_second, 8191 * 8);
  }
  
  void osselect_second(void)
  {
      char *bhs = (char *) *((int *) ADR_BOTPAK);
      int i, *bootpack = (int *) ADR_BOTPAK, *bhs_i = (int *) bhs;
      int *p, *q, datsiz;
      for (i = 0; i < (LIMIT_BOTPAK + 1) / 4; i++) {
          bootpack[i] = bhs_i[i];
      }
      datsiz = (bhs_i[16 / 4] + 3) / 4;
      p = (int *) (bhs_i[20 / 4] + bhs);
      q = (int *) bhs_i[12 / 4];
      for (i = 0; i < datsiz; i++) {
          q[i] = p[i];
      }
      asm_osselect_third(bhs_i[12 / 4]);
  }
  
  void init_gdt(void)
  {
      struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;
      int i;
  
      /* GDTの初期化 */
      for (i = 0; i <= LIMIT_GDT / 8; i++) {
          set_segmdesc(gdt + i, 0, 0, 0);
      }
      set_segmdesc(gdt + 1, 0xffffffff,   0x00000000, AR_DATA32_RW);
      set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER);
      load_gdtr(LIMIT_GDT, ADR_GDT);
  
      return;
  }
  
  void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar)
  {
      (中略)
  }
  
  void memman_init(struct MEMMAN *man)
  {
      (中略)
  }
  
  unsigned int memman_alloc(struct MEMMAN *man, unsigned int size)
  {
      (中略)
  }
  
  int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size)
  {
      (中略)
  }
  
  unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size)
  {
      (中略)
  }
  
  int memman_free_4k(struct MEMMAN *man, unsigned int addr, unsigned int size)
  {
      (中略)
  }
  
 -(中略)の部分はharib27fから同名関数をそのまま持ってきただけ。
 ----
 -Makefile
  
  OBJS_BOOTPACK = bootpack.obj naskfunc.obj tek.obj img_bhs.obj
  
  (中略)
  
  img_bhs.obj : haribote.bhs Makefile
      $(BIN2OBJ) haribote.bhs img_bhs.obj _img_bhs
  
  (中略)
  
 *** 効果は?
 -(以下編集中)
 -(harib27fの場合は、smaller1の結果からさらに7.5KBほど改善し、22.2KBくらいになる。)
 
 *** さらに効果をあげるには?
 -tek圧縮にはいろいろとバリエーションがあり、そのどれを使うのかを決めてしまうことでもっと小さくできるでしょう。tek.cはtek1、tek2、stk5、tek5のすべてに対応していますが、どれにするかをあらかじめ決めてしまえば、tek.cをもっと小さなものに交換することができます。まあでも、これをやってもあと1〜2KBくらいしか小さくならない気がするので、無理してやるほどのことではないかもしれません。
 
 * こめんと欄
 
 #comment

リロード   新規 編集 差分 添付   トップ 一覧 検索 最終更新 バックアップ   ヘルプ   最終更新のRSS