This manual has the purpose of helping software developers understand how they should be using Pure64 to load their kernel.
This manual assumes you have some understanding of a typical boot process.
You'll have to have NASM installed to build the software.
In the top directory of Pure64, just run the following:
./build.sh
A computer with at least one 64-bit Intel or AMD CPU (or anything else that uses the x86-64 architecture)
At least 2 MiB of RAM
The ability to boot via a hard drive, USB stick, or the network
Here's a minimal kernel, written for NASM, that you could use with Pure64.
Once it's loaded, it enters an infinite loop.
The file can be called kernel.asm.
BITS 64
ORG 0x100000
start:
jmp start
The ORG statement tells NASM that the code should be made to run at the address, 0x100000.
Assemble it like this:
nasm kernel.asm -o kernel.bin
Here's a similar example written in C with GCC.
The file can be called kernel.c.
void _start(void) {
for (;;) {
}
}
The kernel needs a linker script to be loaded to 1 MiB, replacing NASMs ORG instruction.
The file can be called kernel.ld.
OUTPUT_FORMAT("binary")
OUTPUT_ARCH("i386:x86-64")
SECTIONS
{
. = 0x100000;
.text : {
*(.text)
}
.data : {
*(.data)
}
.rodata : {
*(.rodata)
}
.bss : {
*(.bss)
}
}
Compile is like this:
gcc -c kernel.c -o kernel.o -mno-red-zone -fno-stack-protector -fomit-frame-pointer
ld -T kernel.ld -o kernel.bin kernel.o
The flags added to the first command are there to help GCC produce could that will run in kernel space. The second command simply takes kernel.o and orders it as the linker script tells it to.
The _start symbol must always appear first within flat binaries as Pure64 will call the start of the file so it must contain executable code. Function definitions (such as inline ones) in header files could interfere with the placement of the _start symbol. The best solution is to put the entry point in a separate file that calls the main function. Such a file could be called start.c.
extern int main(void);
void _start(void)
{
main();
}
This file would always have to be linked in front of everything else. For the above example that would mean the linker command above would have to become:
ld -T kernel.ld -o kernel.bin start.o kernel.o
All Pure64 binaries are in the bin directory.
For BIOS systems you'll need pure64-bios.sys and mbr.sys to be in the same directory as your kernel with the name kernel.bin
dd if=/dev/zero of=disk.img count=128 bs=1048576
cat pure64.sys kernel.bin > software.sys
dd if=mbr.sys of=disk.img conv=notrunc
dd if=software.sys of=disk.img bs=512 seek=16 conv=notrunc
After creating a bootable image it can be tested using qemu:
qemu-system-x86_64 -drive format=raw,file=disk.img
For UEFI systems you'll need pure64-uefi.sys, uefi.sys, and a FAT-formatted drive/partition.
cat pure64-uefi.sys kernel.bin > software-uefi.sys
cp uefi.sys BOOTX64.EFI
dd if=software-uefi.sys of=BOOTX64.EFI bs=4096 seek=1 conv=notrunc > /dev/null 2>&1
The resulting BOOTX64.EFI can be copied to the \EFI\BOOT\ folder on the storage device you plan on booting from.
This memory map shows how physical memory looks after Pure64 is finished.
| Start Address | End Address | Size | Description |
|---|---|---|---|
| 0x0000000000000000 | 0x0000000000000FFF | 4 KiB | IDT - 256 descriptors (each descriptor is 16 bytes) |
| 0x0000000000001000 | 0x0000000000001FFF | 4 KiB | GDT - 256 descriptors (each descriptor is 16 bytes) |
| 0x0000000000002000 | 0x0000000000002FFF | 4 KiB | PML4 - 512 entries, first entry points to PDP at 0x3000 |
| 0x0000000000003000 | 0x0000000000003FFF | 4 KiB | PDP Low - 512 entries |
| 0x0000000000004000 | 0x0000000000004FFF | 4 KiB | PDP High - 512 entries |
| 0x0000000000005000 | 0x0000000000007FFF | 12 KiB | Pure64 Data |
| 0x0000000000008000 | 0x000000000000FFFF | 32 KiB | Pure64 - After the OS is loaded and running this memory is free again |
| 0x0000000000010000 | 0x000000000001FFFF | 64 KiB | PD Low - Entries are 8 bytes per 2MiB page |
| 0x0000000000020000 | 0x000000000005FFFF | 256 KiB | PD High - Entries are 8 bytes per 2MiB page |
| 0x0000000000060000 | 0x000000000009FFFF | 256 KiB | Free |
| 0x00000000000A0000 | 0x00000000000FFFFF | 384 KiB | BIOS ROM Area |
| VGA mem at 0xA0000 (128 KiB) Color text starts at 0xB8000 | |||
| Video BIOS at 0xC0000 (64 KiB) | |||
| Motherboard BIOS at F0000 (64 KiB) | |||
| 0x0000000000100000 | 0xFFFFFFFFFFFFFFFF | 1+ MiB | The software payload is loaded here |
When creating your Operating System or Demo you can use the sections marked free, however it is the safest to use memory above 1 MiB.
Pure64 stores an information table in memory that contains various pieces of data about the computer before it passes control over to the software you want it to load.
The Pure64 information table is located at 0x0000000000005000 and ends at 0x00000000000057FF (2048 bytes).
| Memory Address | Variable Size | Name | Description |
|---|---|---|---|
| 0x5000 | 64-bit | ACPI | Address of the ACPI tables |
| 0x5008 | 32-bit | CPU_BSP_ID | APIC ID of the BSP |
| 0x5010 | 16-bit | CPU_SPEED | Speed of the CPUs in MegaHertz (MHz) |
| 0x5012 | 16-bit | CPU_CORES_ACTIVE | The number of CPU cores that were activated in the system |
| 0x5014 | 16-bit | CPU_CORES_DETECT | The number of CPU cores that were detected in the system |
| 0x5016 | 8-bit | CPU_MEM_PHYSICAL | The number of bits that are valid for a physical address |
| 0x5017 | 8-bit | CPU_MEM_VIRTUAL | The number of bits that are valid for a virtual address |
| 0x5018 | 32-bit | CPU_ID_MAX_STANDARD | The maximum CPUID standard leaf |
| 0x501C | 32-bit | CPU_ID_MAX_EXTENDED | The maximum CPUID extended leaf |
| 0x5020 | 32-bit | RAMAMOUNT | Amount of system RAM in Mebibytes (MiB) |
| 0x5022 - 0x502F | For future use | ||
| 0x5030 | 8-bit | IOAPIC_COUNT | Number of I/O APICs in the system |
| 0x5031 | 8-bit | IOAPIC_INTSOURCE_COUNT | Number of I/O APIC Interrupt Source Override |
| 0x5032 - 0x503F | For future use | ||
| 0x5040 | 64-bit | HPET Address | Base memory address for the High Precision Event Timer |
| 0x5048 | 32-bit | HPET Frequency | Frequency for the High Precision Event Timer |
| 0x504C | 16-bit | HPET Counter Minumum | Minimum Counter for the High Precision Event Timer |
| 0x504E | 8-bit | HPET Counters | Number of Counter in the High Precision Event Timer |
| 0x504F | For future use | ||
| 0x5060 | 64-bit | LAPIC | Local APIC address |
| 0x5068 - 0x507F | For future use | ||
| 0x5080 | 64-bit | VIDEO_BASE | Base memory for video (if graphics mode set) |
| 0x5088 | 16-bit | VIDEO_X | X resolution |
| 0x508A | 16-bit | VIDEO_Y | Y resolution |
| 0x508C | 16-bit | VIDEO_PPSL | # of pixels per scan line |
| 0x508E | 16-bit | VIDEO_BPP | # of bits per pixel |
| 0x5090 | 16-bit | PCIE_COUNT | Number of PCIe buses |
| 0x5092 | 16-bit | IAPC_BOOT_ARCH | IA-PC Boot Architecture Flags |
| 0x5094 - 0x50DF | For future use | ||
| 0x50E0 | 8-bit | FLAG_1GBPAGE | 1 if 1GB Pages are supported |
| 0x50E1 | 8-bit | FLAG_X2APIC | 1 if X2APIC is supported |
| 0x50E2 | 8-bit | FLAG_BOOTMODE | 'B' if BIOS, 'U' for UEFI |
| 0x50E3 - 0x50FF | For future use | ||
| 0x5100 - 0x51FF | 8-bit | APIC_ID | APIC ID's for valid CPU cores (based on CORES_ACTIVE) |
| 0x5200 - 0x53FF | For future use | ||
| 0x5400 - 0x55FF | 16 byte entries | PCIE | PCIe bus data |
| 0x5600 - 0x56FF | 16 byte entries | IOAPIC | I/O APIC addresses (based on IOAPIC_COUNT) |
| 0x5700 - 0x57FF | 8 byte entries | IOAPIC_INTSOURCE | I/O APIC Interrupt Source Override Entries (based on IOAPIC_INTSOURCE_COUNT) |
PCIE list format:
| Offset | Variable Size | Name | Description |
|---|---|---|---|
| 0x00 | 64-bit | Base | The base address of enhanced configuration mechanism |
| 0x08 | 16-bit | Group | The PCI segment group number |
| 0x0A | 8-bit | Start Bus | Start PCI bus number decoded by this host bridge |
| 0x0B | 8-bit | End Bus | End PCI bus number decoded by this host bridge |
| 0x0C | 32-bit | Reserved | This value should be 0 |
IOAPIC list format:
| Offset | Variable Size | Name | Description |
|---|---|---|---|
| 0x00 | 32-bit | I/O APIC ID | The ID of an I/O APIC |
| 0x00 | 32-bit | I/O APIC Address | The 32-bit physical address to access this I/O APIC |
| 0x00 | 32-bit | Global System Interrupt Base | The global system interrupt number where this I/O APIC’s interrupt inputs start |
| 0x00 | 32-bit | Reserved | This value should be 0 |
IOAPIC_INTSOURCE list format:
| Offset | Variable Size | Name | Description |
|---|---|---|---|
| 0x00 | 8-bit | Bus | 0 |
| 0x00 | 8-bit | Source | Bus-relative interrupt source |
| 0x00 | 32-bit | Global System Interrupt | The Global System Interrupt that this bus-relative interrupt source will signal |
| 0x00 | 16-bit | Flags | MPS INTI flags |
MPS INTI flags:
| Flags | Bit Length | Bit Offset | Description |
|---|---|---|---|
| Polarity | 2 | 0 | 01 Active high, 11 Active low |
| Trigger Mode | 2 | 2 | 01 Edge-triggered, 11 Level-triggered |
A copy of the BIOS System Memory Map is stored at memory address 0x0000000000006000. Each BIOS record is 32 bytes in length and the memory map is terminated by a blank record.
| Variable | Variable Size | Description |
|---|---|---|
| Base | 64-bit | Base Address |
| Length | 64-bit | Length in bytes |
| Type | 32-bit | Type of memory (1 is usable) |
| ACPI | 32-bit | See document linked below |
A copy of the UEFI System Memory Map is stored at memory address 0x0000000000220000. Each UEFI record is 48 bytes in length and the memory map is terminated by a blank record.
| Variable | Variable Size | Description |
|---|---|---|
| Type | 64-bit | The type of the memory region |
| Physical Start | 64-bit | Physical Address - 4K aligned |
| Virtual Start | 64-bit | Virtual Address - 4K aligned |
| NumberOfPages | 64-bit | The number of 4K pages in this section |
| Attribute | 64-bit | See document linked below |
| Padding | 64-bit | Padding |
Pure64 initializes the serial port COM1 at 115200bps, 8 data bytes, 1 stop bit, no parity, and no flow control. It will display messages on boot-up.
// EOF