Hello,
I’m having an issue I haven’t come across before, namely that the Code Generation step seems to spin endlessly (longer than I expect it should take, it has run 5 or 10 minutes by now).
Main builds and runs, but not gc-2024-09-24-gdt.
It seems to be specifically related to the presence of the makeGdtEntry
call(s). It will compile and run if I take those calls out.
I am not sure what’s wrong here, any insight would be much appreciated ^_^
Zig Version 0.13.0
> zigup run 0.13.0 build
[0/3] steps
└─ [2] zig build-exe kernel.elf Debug x86-frees
├─ [132] Semantic Analysis
│ ├─ gdt.gdt_entries
│ └─ gdt.init
└─ [19] Code Generation
Zig Version 0.14.0-dev.1637+8c232922b
> zigup run master build
[0/3] steps
└─ [3] zig build-exe kernel.elf Debug x86-frees
├─ [137] Semantic Analysis
│ ├─ gdt.gdt_entries
│ └─ gdt.init
└─ [2] Code Generation
Relevant Code Samples (from src/gdt.zig)
/// The GDT entry table containing NUMBER_OF_ENTRIES entries.
var gdt_entries: [NUMBER_OF_ENTRIES]GdtEntry = .{
// Null descriptor
makeGdtEntry(0, 0, NULL_SEGMENT, NULL_FLAGS),
// Kernel code descriptor
// makeGdtEntry(0, 0xFFFFF, KERNEL_SEGMENT_CODE, PAGING_32_BIT),
// Kernel data descriptor
// makeGdtEntry(0, 0xFFFFF, KERNEL_SEGMENT_DATA, PAGING_32_BIT),
// User code descriptor
// makeGdtEntry(0, 0xFFFFF, USER_SEGMENT_CODE, PAGING_32_BIT),
// User data descriptor
// makeGdtEntry(0, 0xFFFFF, USER_SEGMENT_DATA, PAGING_32_BIT),
// TSS descriptor, one each for each processor.
// Will initialize the TSS at runtime.
// makeGdtEntry(0, 0, NULL_SEGMENT, NULL_FLAGS),
};
///
/// Make a GDT entry.
///
/// Arguments:
/// IN base: u32 - The linear address where the segment begins.
/// IN limit: u20 - The maximum addressable unit whether it is 1B units or page units.
/// IN access: AccessBits - The access bits for the descriptor.
/// IN flags: FlagBits - The flag bits for the descriptor.
///
/// Return: GdtEntry
/// A new GDT entry with the given access and flag bits set.
///
fn makeGdtEntry(base: u32, limit: u20, access: AccessBits, flags: FlagBits) GdtEntry {
return .{
.limit_low = @truncate(limit),
.base_low = @truncate(base),
.access = .{
.accessed = access.accessed,
.read_write = access.read_write,
.direction_conforming = access.direction_conforming,
.executable = access.executable,
.descriptor = access.descriptor,
.privilege = access.privilege,
.present = access.present,
},
.limit_high = @truncate(limit >> 16),
.flags = .{
.reserved_zero = flags.reserved_zero,
.is_64_bit = flags.is_64_bit,
.is_32_bit = flags.is_32_bit,
.granularity = flags.granularity,
},
.base_high = @truncate(base >> 24),
};
}
pub fn init() void {
console.printf("NUMBER_OF_ENTRIES: {}\n", .{NUMBER_OF_ENTRIES});
console.printf("TABLE_SIZE: {}\n", .{TABLE_SIZE});
console.printf("KERNEL_SEGMENT_CODE: {}\n", .{KERNEL_SEGMENT_CODE});
console.printf("gdt_entries[0]: {}\n", .{gdt_entries[0]});
...
}
Using gdt_entries[0] is enough to get the whole thing to start stalling, assuming there’s a makeGdtEntry
call in there.
Bonus Screenshot