FreeBSDとGRUB

こんにちは この記事は、GRUBに対する私の個人的な闘いに捧げられています。

もちろん、grub-loaderをfreebsdに配置する必要がありました。もちろん、多くの人がchainloader + 1について知っていますが、この方法は私には適していません。





前戯




だから、シデを入れてください(最初は、2番目はあまりにも怪しいようです):

# cd /usr/ports/sysutils/grub && make install





次に、実際にブートローダーとして登録する必要があります

# grub-install /dev/ad8





これが問題が起こった場所です。 不幸なニュース- 「ファイル/ブート/ grub / stage1が正しく読み取れません。」

どうして? ホーンビームがインストールされているかどうかを確認したとき、私自身はこのファイルを見ました。

さて、ログを見てみましょう:

# cat /tmp/grub-install.log.XXXXX

grub> dump (hd2,0,a)/boot/grub/stage1 /tmp/grub-install.img.XXXXX



Error 22: No such partition

grub> quit








セクション自体がそうであるので、エラーは私に何も教えません。 Googleは、ext3に大きなサイズのiノードがあるバグを除いて助けにはなりませんでしたが、ufsがあり、サイズは固定され、128バイトに等しいです。 したがって、コードは設計と構造の点でひどく書かれているという事実にもかかわらず、私は自分でそれを掘ることに決めました。



エラー22




このエラーに対応する定数を定義することから調査を開始します-ERR_NO_PART 、そしてこのエラーを返すことができる人を探します(実際には、grub'eにいくつかのアナログerrnoが実装されています。つまり、最後のエラーの番号を含むグローバル変数です)。

そのような場所は2つしかなく、2つの隣接するラムダ関数(hello gcc!)に配置されています。Next_bsd_partition()およびnext_pc_slice() 、すべてが名前で明確です-2番目はbsdスライスをリストし、最初はこれらのスライスのセクションをリストします。



grubコードの構造のために、静的分析のアイデアをすぐに却下しました。非常に多くのグローバル変数があり、関数への引数はほとんどありません。 また、これについてはあまり経験がなく、すべてがリモートサーバーで発生したため、実際にはgdbでデバッグしたくありませんでした。したがって、xxgdbを使用することはできませんでした。 したがって、私は初心者の単純なアプローチを選択しました-私たちは不明瞭な場所にprintfsを挿入します。 ここでも私は困難がありました:







実際には、より迅速なチェックが必要でした。毎回ホーンビームコンソールにアクセスしたり、2行入力したりしないでください。 これは、単純なコマンド(grub-installシェルスクリプトで調べた)によって実現されます。

./grub/grub --batch < cmd





cmdにコマンドのリストが含まれる場合、この場合は次のようになります。

dump (hd2,0,a)/boot/grub/stage1 test_img

quit








職場の準備ができたら、「デバッグ」を開始します。 これらの2つの関数の先頭にprintf()を挿入し、つまずいた階層のレベルを確認します。

セクションにつまずいたのですが、ここにそのようなサイクルがあります:

  /* Search next valid BSD partition. */ for (i = bsd_part_no + 1; i < BSD_LABEL_NPARTS (buf); i++) { if (BSD_PART_TYPE (buf, i)) { /* Note that *TYPE and *PARTITION were set for current PC slice. */ *type = (BSD_PART_TYPE (buf, i) << 8) | (*type & 0xFF); *start = BSD_PART_START (buf, i); *len = BSD_PART_LENGTH (buf, i); *partition = (*partition & 0xFF00FF) | (i << 8); #ifndef STAGE1_5 /* XXX */ if ((drive & 0x80) && BSD_LABEL_DTYPE (buf) == DTYPE_SCSI) bsd_evil_hack = 4; #endif /* ! STAGE1_5 */ return 1; } }
      
      





ところで、開発者の興味深い位置に注意を払うことができます-インデントは、タブとスペースの組み合わせ、つまり、2つのタブ、4つのスペースを使用して実装されます。 編集者が実際にコードを編集した「好き」なもの。

BSD_PART_TYPE(buf、i)条件が機能しなかった場合、私たちは貴族が終了したと結論付けます。



 #define BSD_PART_TYPE(l_ptr, part) \ ( *( (unsigned char *) (((int) l_ptr) + BSD_PART_OFFSET + 12 \ + (part << 4)) ) )
      
      





この定義は「非常に」理解可能です。 明確にするために、私はCPJ Koymans博士のBooting、Partitioning and File Systemsに行かなければなりませんでした。

そこにスライスの構造が表示されます。1つのセクションの記述ブロックからのオフセット12に[ パーティションタイプ]フィールドがあり、条件が機能しないため、0であるように見えます。

-bsdlabel / dev / ad8s1を確認しますが 、実際には使用されていないことを示しています。 さて、短命のもの-bsdlavel -e / dev / ad8s1を修正してください 。 しかし、彼はしたくない-「クラスが見つかりません」。

もちろん、hornbeamをインストールする前に、フラグ( sysctl kern.geom.debugflags = 16 )を設定し、グーグルで検索し 、フリークの最新バージョンに17を追加して設定することをお勧めします-結果はありません。



bsdlabelの種類を掘り下げたいという望みはなかったので、 ktrace bsdlabel -e / dev / ad8s1を実行してからkdump |実行する方が簡単でした もっと

74340 bsdlabel CALL open(0x28201030,O_RDWR,[unused]0xbfbfe9e8)

74340 bsdlabel NAMI "/dev/ad8s1"

74340 bsdlabel RET open -1 errno 1 Operation not permitted

74340 bsdlabel CALL open(0x28097653,O_RDONLY,[unused]0x28050629)

74340 bsdlabel NAMI "/dev/geom.ctl"

74340 bsdlabel RET open 3

74340 bsdlabel CALL ioctl(0x3,GEOM_CTL,0x28203040)

74340 bsdlabel RET ioctl 0






「操作は許可されていません」、明らかにbsdlabelを使用してシステムドライブをオンザフライで編集する運命ではありません。

しかし、大丈夫です-gpartがあります:

gpart modify -i 1 -t freebsd-ufs /dev/ad8s1





インデックス1。セクション 'a'のようなロジックを修正するため。 / dev / ad8s1ではなく/ dev / ad8。スライステーブル(私の場合はMBR)ではなく、スライス自体を編集しているためです。

bsdlabel'om-成功を確認してください。 指を交差させて、シデがこれにどのように反応するかを確認します。 彼は積極的に反応したが、最後まで反応しなかった。 エラー22は新しいものに置き換えられました- エラー17:選択されたパーティションをマウントできません



エラー17




名前からすべてが明らかです-ufsのマウントに関するエラー。 ただし、あまり面倒ではなく、シグナルprintfをufs2_mount()に入れます。

そうです。 関数は失敗します。 理由も明らかです-スーパーブロックが見つかりません。 これは、FSに関する基本情報(ノードのサイズ、クラスターのサイズ、フラグなど)を含む構造です。

FSアーキテクチャではかなり一般的な構造であり、ufs2にもありますが、grubはそれを見つけません。 彼女が「座っている」場所を見てみましょう-dumpfs / | head -2は、そのような行"superblock location 65536"を生成します。

グラブを見る:

 #define SBLOCK_FLOPPY 0 #define SBLOCK_UFS1 8192 #define SBLOCK_UFS2 65536 #define SBLOCK_PIGGY 262144 #define SBLOCKSIZE 8192 #define SBLOCKSEARCH \ { SBLOCK_UFS2, SBLOCK_UFS1, SBLOCK_FLOPPY, SBLOCK_PIGGY, -1 }
      
      





大切な番号が表示されています。見つけてみませんか?

65536はバイト単位のオフセットであり、私が確実に確信できなかったと考えられるものに関しては、マージンを持ってそれを取りました。

dd if=/dev/ad8 bs=512 count=200 | hexdump -C | grep 54





最初の200セクターを読み取ります(セクション自体は16セクターで始まり、128(スーパーブロックオフセット)+ 16(最大参照ポイント)+ 16(スーパーブロックサイズ)<200、信頼性のためのバックラッシュ)。

grep 54-スーパーブロックの署名にあるバイト0x54を含む文字列を取得します。署名の合計サイズは4バイトです。

#define FS_UFS2_MAGIC 0x19540119 /* UFS2 fast filesystem magic number */





しかし、すぐにdwordで検索する方法は発生しなかったので、数十行を見ました。 シグニチャは69セクタで2回完全に見つかり、混乱しました。 ダンプを詳しく調べたところ、さらにFS_UFS1_MAGICに言及しているため、これはおそらくスーパーブロック自体ではなくローダーコードです。



それから、セクションの内部を見る方が良いと思いました:

dd if=/dev/ad8s1a bs=512 count=200 | hexdump -C | grep 54





そして、ここで成功が私を待っていました-オフセット0x10550(66896)で私たちの署名が見えます。

署名はスーパーブロックの先頭ではなくスーパーブロックの最後にあるため、オフセットは正確には65536ではありません。したがって、8192未満の「デルタ」( FIELD_OFFSET() )が追加されます。

ご覧のとおり、スーパーブロックが存在し、正確には、セクションの先頭からのオフセットが予想される場所にあります。 相対オフセットを定義し、既知の検索文字列で最初のnセクターを愚かに調べます。

-0001a350(107344)を取得しますが、これは209番目のセクターに相当します。 これは、スライス自体の先頭を追加するのを忘れたため(63)、63 + 16 + 128 == 207、

また、2つのセクターがスーパーブロックの残りのフィールドを占有します。

ターゲットセクターは、 devread(セクター、byte_offset)で簡単に計算されます。

sector + (byte_offset >> SECTOR_BITS) + part_start





変数sectorおよびbyte_offsetは、この例ではそれぞれ0および65536に等しい引数であり、もちろん正しいです。 しかし、 part_startは16を生成します。これも事実です。 しかし、ホーンビームはこれを、スライスの開始ではなく、ディスクの開始に相対的な絶対値として認識します。

マナは「 セクターのドライブの先頭からのパーティションの開始のオフセット 」と言いますが、同時に「 最初のパーティションはオフセット16で始まるはずです 」と言います。

しかし、システムは機能し、すべてが正常にマウントされるため、バグはシデにあるようです。 したがって、1文字のみを追加して修正します。

*start += BSD_PART_START (buf, i);





そして今、すべてが成功しています-part_start = 0x4F 、ダンプが実行されます。

再構築されたホーンビームを使用して、修正がstage1_5 / stage2に入るようにします

grub_installは正しく動作し、すべてが正常です。



読み取りファイルのサイズ制限




少しオフトピックですが、ufs、grub'a、およびfryakhaに関係します。

grubが読み取れる最大ファイルサイズ:

(12 + superblock.nindir) * superblock.bsize







スーパーブロックパラメーターは、dumpfsログから取得されます。

私はシステム上で約32メートルを取得しましたが、これは私にとってあまり喜ばしいことではないので、コードからチェックを外しました。

これを行うには、 fsys_ufs2.cのこの行にコメントします

fsmax = (NDADDR + NINDIR (SUPERBLOCK)) * SUPERBLOCK->fs_bsize;









フィニータ




ここに、私がフリークでどのようにグラブを実行したかについての小さな話があります。

ここで役立つもの:




All Articles