我已经设置了32位保护模式,并尝试通过C和汇编加载全局描述符表(GDT),并尝试通过check_gdt()函数打印不同的寄存器值,其中
void check_gdt() {
uint16_t cs, ds, es, fs, gs, ss;
// Inline assembly to get the values of segment registers
asm volatile("mov %%cs, %0" : "=r"(cs));
asm volatile("mov %%ds, %0" : "=r"(ds));
asm volatile("mov %%es, %0" : "=r"(es));
asm volatile("mov %%fs, %0" : "=r"(fs));
asm volatile("mov %%gs, %0" : "=r"(gs));
asm volatile("mov %%ss, %0" : "=r"(ss));
// Print the segment register values
printf("CS: 0x%x\n", cs);
printf("DS: 0x%x\n", ds);
printf("ES: 0x%x\n", es);
printf("FS: 0x%x\n", fs);
printf("GS: 0x%x\n", gs);
printf("SS: 0x%x\n", ss);
}
通过以下方式初始化GDT
void initGdt(){
gdt_ptr.limit = (sizeof(struct gdt_entry_struct) * 5) - 1;
gdt_ptr.base = (uint32_t)&gdt_entries;
setGdtGate(0,0,0,0,0); // Null segment _________________ _______________
// Explanation: |P|DPL|S|E|DC|RW|A| |G|DB|L|Res| |
setGdtGate(1,0,0xFFFFFFFF, 0x9A, 0xCF); // Kernel code segment : access = 0x9A =>|1|00 |1|1|0 |1 |0|, gran = 0xCF => |1|1 |0|0 |1111|
setGdtGate(2,0,0xFFFFFFFF, 0x92, 0xCF); // Kernel data segment : access = 0x92 =>|1|00 |1|0|0 |1 |0|, gran = 0xCF => |1|1 |0|0 |1111|
// _________________ _______________
setGdtGate(3,0,0xFFFFFFFF, 0xFA, 0xCF); // User code segment : access = 0xFA =>|1|11 |1|1|0 |1 |0|, gran = 0xCF => |1|1 |0|0 |1111|
setGdtGate(4,0,0xFFFFFFFF, 0xF2, 0xCF); // User data segment : access = 0x9A =>|1|11 |1|0|0 |1 |0|, gran = 0xCF => |1|1 |0|0 |1111|
// ----------------- ---------------
gdt_flush((uint32_t) &gdt_ptr);
}
void setGdtGate(uint32_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran){
gdt_entries[num].base_low = (base & 0xFFFF); // Assign lower base 16 bit
gdt_entries[num].base_middle = (base >> 16) & 0xFF; // Assign middle base 8 bit
gdt_entries[num].base_high = (base >> 24) & 0xFF; // Assign higher base 8 bit
gdt_entries[num].limit_low = (limit & 0xFFFF); // Assign lower limit 16 bit
gdt_entries[num].flags = (limit >> 16) & 0x0F; // Assign flags lower 4 bit
gdt_entries[num].flags |= (gran & 0xF0); // Assign flags upper 4 bit
gdt_entries[num].access = access; // Assign access 8 bit
}
并通过gdt_flush函数将GDT加载到CPU中
gdt_flush:
; [esp] Return address (from CALL)
; Load the address of the GDT descriptor
MOV eax, [esp + 4] ; To load the content of [esp+4] address which is the first argument of gdt_flush((uint32_t) &gdt_ptr)
LGDT [eax] ; Load the GDT into the CPU
MOV ax, 0x10 ; Load kernel data segment selector (0x10)
MOV ds, ax ; Set data segment register to kernel data segment
MOV es, ax ; Set extra segment register to kernel data segment
MOV fs, ax ; Set general-purpose segment to kernel data segment
MOV gs, ax ; Set general-purpose segment to kernel data segment
MOV ss, ax ; Set stack segment to kernel data segment
JMP 0x08:.flush ;Far jump to selector 0x08 (code segment) and the address of flush
; Entry 1: Kernel code segment (selector = 0x08)
.flush:
RET
我期待上面的 gdt 加载
CS : 0x08
DS : 0x10
ES : 0X10
FS : 0X10
GS : 0X10
SS : 0X10
是的@Jester和@ Michael Petch 都是对的,我的 printf 函数被破坏了。我正在使用 print_hex(cs) ...在 print_hex 所在的地方工作得很好
// 将十六进制数输出到屏幕。无效 print_hex(uint32_t n) { char hex_chars[] = "0123456789ABCDEF"; 打印(“0x”);
for (int i = 28; i >= 0; i -= 4) // process each nibble (4 bits) { putchar(hex_chars[(n >> i) & 0xF]); } }