3

私は最近、カーネル開発に夢中になり、OSDev Wiki の基本的なチュートリアルから始めました。Hello World の例を実装した後、次に進み、Global Descriptor Table の作成を試みました。オンラインのさまざまなソースから、GDT のコードをつなぎ合わせましたが、最終的には失敗しました。これの私の実装に何か問題がありますか?それがすぐに明らかにならない場合、より多くの情報を提供できるソースはありますか?

つまり、GDT を使用したカーネルの次の実装は、GRUB を使用したロードに失敗します。gccandでコンパイルしていasます。必要なその他の情報を提供できます。

ブーツ

.section .text
.global _start
.type _start, @function
_start:
    movl $stack_top, %esp
    call kernel_main
    cli
    hlt
.Lhang:
    jmp .Lhang
.size _start, . - _start

.global gdt_flush

gdt_flush:
    cli
    movl    -4(%esp), %eax
    lgdt    (%eax)
    movw    $0x10, %ax
    movw    %ax, %ds
    movw    %ax, %es
    movw    %ax, %fs
    movw    %ax, %gs
    movw    %ax, %ss            //the inclusion of this line or the following
    jmp $0x08, $.flush      //prevents the kernel from loading
.flush: 
    ret

.section .bootstrap_stack
stack_bottom:
.skip 16384
stack_top:

カーネル.c

void kernel_main() {
    gdt_install();
    ...
}

gdt.c

struct gdt_entry {
  uint16_t limit_low;
  uint16_t base_low;
  uint8_t base_middle;
  uint8_t access;
  uint8_t granularity;
  uint8_t base_high;
}__attribute__((packed));

struct gdt_ptr {
  uint16_t limit;
  uint32_t base;
}__attribute__((packed));

struct gdt_entry gdt[3];
struct gdt_ptr gp;

extern void gdt_flush(struct gdt_ptr *);

void gdt_set_gate(uint32_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran) {
  gdt[num].base_low = (base & 0xFFFF);
  gdt[num].base_middle = (base >> 16) & 0xFF;
  gdt[num].base_high = (base >> 24) & 0xFF;

  gdt[num].limit_low = (limit & 0xFFFF);
  gdt[num].granularity = (limit >> 16) & 0x0F;

  gdt[num].granularity |= (gran & 0x0F);
  gdt[num].access = access;
}

void gdt_install() {
  gp.limit = (sizeof(struct gdt_entry) * 3) - 1;
  gp.base = (uint32_t) &gdt;

  gdt_set_gate(0, 0, 0, 0, 0);
  gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF);
  gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF);

  gdt_flush(&gp);
}
4

1 に答える 1

2

いくつかの問題があるようです。私はあなたの GDT エントリの特定のビットをチェックしませんでした (これは、Intel のマニュアルを手元に置いて自分で行わなければならない作業です)。

GDT は 20 ビットでしか動作しませんが、最初に (これは現在は問題を引き起こしませんが、将来的には問題を引き起こす可能性があります)、4 バイト幅の制限を指定して動作させることです。gdt_install20 ビットの制限のみを渡すように関数を変更し、将来の使用のためにコメントで文書化する必要があります。もう 1 つの解決策は、もちろんパラメーターを 12 ビット右にシフトすることですが、これはあまり意味がなく、次に GDT 管理に戻ったときに説明が異なる可能性があります。

正しくないように思われる 2 番目のことは、 のパラメーターを取得する方法ですgdt_flush。スタックは下に向かって成長するため、最後にプッシュされた項目は(命令(%esp)によってプッシュされた戻りアドレス) に配置され、必要なパラメーターは に配置されます。call4(%esp)

あなたはすでにプロテクト モードにあり、実際の G​​DT はブート ローダーによって既にセットアップされていると仮定します。そのため、別のファー ジャンプ (少なくとも 3 クロックを消費する) の明らかな理由はわかりませんが、そのコードが常に正しいとは限りません。セグメントはヌル セグメントの直後に配置されます。そのジャンプで気に入らないのは、ジャンプ先として使用されるラベルです。絶対値が必要な大きなジャンプなので、チェックすることをお勧めします。

于 2013-08-15T09:03:41.583 に答える