Skip to content

Instantly share code, notes, and snippets.

@graphitemaster
Created October 14, 2012 00:17
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save graphitemaster/3886709 to your computer and use it in GitHub Desktop.
Save graphitemaster/3886709 to your computer and use it in GitHub Desktop.
gmbootloader
#include "config.h"
/*
* The initial entry point called by the bootloader assembly routine stuff
* this is stage 2 (so to speak)
*/
void gmboot_entry(void) {
}
#ifndef GMBOOT_CONFIG_HDR
#define GMBOOT_CONFIG_HDR
#define GMBOOT_EXTMEM 0x100000 /* start of extended memory */
#define GMBOOT_PHYTOP 0xE000000 /* top of physical memory */
#define GMBOOT_DEVBEG 0xFE00000 /* device address space */
#define GMBOOT_KERNEL 0x8000000 /* first kernel virtual address */
/*
* Configuration settings below shouldn't need to be changed ever,
* unless you're a pro doing some serious crazy shit :P.
*/
/* address where kernel is linked */
#define GMBOOT_LINKED (GMBOOT_KERNEL + GMBOOT_EXTMEM)
/*
* Conversion between virtual and physical addresses used for the
* bootloaders C code
*/
#define GMBOOT_VIRT2PHYS(A) (((unsigned int)(A)) - GMBOOT_KERNEL)
#define GMBOOT_PHYS2VIRT(A) (((void *) (A)) + GMBOOT_KERNEL)
#endif
#include "config.h"
/*
* Some helper macros to better visualize how the GDT works, based on the X86 MMU
* these constants are pulled from the intel software manuals
*/
#define SEG_NULLASM \
.word 0, 0; \
.byte 0, 0, 0, 0
#define SEG_ASM(TYPE,BASE,LIMIT) \
.word (((LIMIT) >> 12) & 0xFFFF), ((BASE) & 0xFFFF); \
.byte (((BASE) >> 16) & 0xFF), (0x90 | (TYPE)), (0xC0 | (((LIMIT) >> 28) & 0xF)), (((BASE) >> 24) & 0xFF)
#define STA_X 0x8 /* executable */
#define STA_E 0x4 /* expand down (non executable) */
#define STA_C 0x4 /* conforming code (executbale only) */
#define STA_W 0x2 /* writable (non-executable) */
#define STA_R 0x2 /* readable (executable) */
#define STA_A 0x1 /* accessed */
/*
* Start the CPU in 16 bit mode, switches to 32-bit protected mode, and enters C
* the BIOS will load this code from the FIRST sector of the HDD into memory at
* physical address 0x7C00, and will start executing in real mode with %cs=0 and
* %ip=0x7C00. Once the A20-line is set it will long jump into 32-bit protected
* mode and call the second-stage boot-loader C code.
*/
.code16
.global gmboot_start
gmboot_start:
cli
// clear data and segment registers
xorw %ax,%ax
movw %ax,%ds
movw %ax,%es
movw %ax,%ss
// test and set A20 line
#define WAIT_A20(X) \
inb $0x64, %al; \
testb $0x02, %al; \
jnz X
gmboot_a20_beg:
WAIT_A20(gmboot_a20_beg)
movb $0xD1, %al
outb %al, $0x64
gmboot_a20_set:
WAIT_A20(gmboot_a20_set)
movb $0xDF, %al
outb %al, $0x60
/*
* Switch from real to protected memory mode. This requires
* a boot-straped GDT that makes virtual addresses map to
* physicals ones, so that the effective memory map doesn't
* change during the transition into A20.
*/
lgdt gmboot_gdtdesc
movl %cr0, %eax
orl $1, %eax /* CRO_PE: protection enabled is 1 */
movl %eax, %cr0
/*
* We now have set the A20 line, we can now jump into our 32-bit
* protected mode by using a long jump to reload %cs and %eip.
* The segement descriptors are set up with no translation to
* allow us to keep the mapping as the identity mapping.
*/
ljmp $(1 << 3), $gmboot_main
.code32
.extern gmboot_entry
gmboot_main:
movw $(1 << 3), %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %ss
movw $0, %ax
movw %ax, %fs
movw %ax, %gs
/*
* Write the stage description piece, then jump into stage2
* where all the magic happens :)
*/
mov $65, %al
call gmboot_putch
/*
* Setup the protected-mode data segment registers, then we can
* setup our stack pointer to call into the actual bootloaders
* C code.
*/
movl $gmboot_start, %esp
call gmboot_entry
/*
* gmboot_entry shouldn't return, unless there is some serious
* problems. So we can trigger a break-point for bochs for
* debugging, this is a feature :)
*/
#ifdef GMBOOT_DEBUG
movw $0x8A00, %ax
movw %ax, %dx
outw %ax, %dx
movw $0x8AE0, %ax
outw %ax, %dx
/*
* Once entered it will never return/exit
* (required for debuggin in bochs)
*/
jmp gmboot_halt
#endif
/*
* Used to halt if there is an error in the first-stage bootloader
* think of this is a for(;;)
*/
gmboot_halt:
jmp gmboot_halt
/*
* Bootstraped global descriptor table, this needs to be aligned
* for 4-bytes.
*/
.p2align 2
gmboot_gdt:
SEG_NULLASM
SEG_ASM(STA_X|STA_R, 0x0, 0xFFFFFFFF)
SEG_ASM(STA_W, 0x0, 0xFFFFFFFF)
gmboot_gdtdesc:
.word (gmboot_gdtdesc - gmboot_gdt - 1) /* sizeof(gmboot_gdt) - 1 */
.long gmboot_gdt /* addr of descriptor table */
.org 510, 0
.byte 0x55
.byte 0xAA
CFLAGS = -nostdinc -nostdlib -ffreestanding -m32 -fno-pic
CC ?= gcc
DD ?= dd
OBJDUMP = objdump
OBJCOPY = objcopy
HEXDUMP = hexdump
boot: main.S boot.c
$(CC) $(CFLAGS) -c boot.c
$(CC) $(CFLAGS) -c main.S
$(LD) -m elf_i386 -N -e gmboot_start -Ttext 0x7C00 -o boot.bin main.o boot.o
$(OBJCOPY) -S -O binary -j .text boot.bin boot.bin
$(DD) if=/dev/zero of=boot.img bs=512 count=1
$(DD) if=boot.bin of=boot.img conv=notrunc bs=512
$(HEXDUMP) -C boot.img
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment