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
After creating a kernel this is a possible routine to create a bootable image.
The commands require Pure64 to be build and pure64.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
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 | 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 | BSP_ID | APIC ID of the BSP |
| 0x5010 | 16-bit | CPUSPEED | Speed of the CPUs in MegaHertz (MHz) |
| 0x5012 | 16-bit | CORES_ACTIVE | The number of CPU cores that were activated in the system |
| 0x5014 | 16-bit | CORES_DETECT | The number of CPU cores that were detected in the system |
| 0x5016 - 0x501F | For future use | ||
| 0x5020 | 32-bit | RAMAMOUNT | Amount of system RAM in Mebibytes (MiB) |
| 0x5022 - 0x502F | For future use | ||
| 0x5030 | 8-bit | IOAPIC_COUNT | Number of IO-APICs in the system |
| 0x5031 - 0x503F | For future use | ||
| 0x5040 | 64-bit | HPET | Base memory address for the High Precision Event Timer |
| 0x5048 - 0x505F | For future use | ||
| 0x5060 | 64-bit | LAPIC | Local APIC address |
| 0x5068 - 0x507F | 64-bit | IOAPIC | IO-APIC addresses (based on IOAPIC_COUNT) |
| 0x5080 | 32-bit | VIDEO_BASE | Base memory for video (if graphics mode set) |
| 0x5084 | 16-bit | VIDEO_X | X resolution |
| 0x5086 | 16-bit | VIDEO_Y | Y resolution |
| 0x5088 | 8-bit | VIDEO_DEPTH | Color depth |
| 0x5089 - 0x50FF | For future use | ||
| 0x5100... | 8-bit | APIC_ID | APIC ID's for valid CPU cores (based on CORES_ACTIVE) |
A copy of the E820 System Memory Map is stored at memory address 0x0000000000006000. Each E820 record is 32 bytes in length and the memory map is terminated by a blank record.
| Variable | Variable Size | Description |
|---|---|---|
| Starting Address | 64-bit | The starting address for this record |
| Length | 64-bit | The length of memory for this record |
| Memory Type | 32-bit | Type 1 is usable memory, Type 2 is not usable |
| Extended Attributes | 32-bit | ACPI 3.0 Extended Attributes bitfield |
| Padding | 64-bit | Padding for 32-byte alignment |