Last active
February 25, 2023 05:35
-
-
Save CodingKoopa/75a60df04316975b778259582dca2ee8 to your computer and use it in GitHub Desktop.
dumb attempt at xv6 bootloader reporting progress over serial (needs to be compiled with `-Os`) [might not actually be correct lol]
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Boot loader. | |
// | |
// Part of the boot block, along with bootasm.S, which calls bootmain(). | |
// bootasm.S has put the processor into protected 32-bit mode. | |
// bootmain() loads an ELF kernel image from the disk starting at | |
// sector 1 and then jumps to the kernel entry routine. | |
#include "types.h" | |
#include "elf.h" | |
#include "x86.h" | |
#include "memlayout.h" | |
#define SECTSIZE 512 | |
#define COM1 0x3f8 | |
void readseg(uchar*, uint, uint); | |
void | |
bootmain(void) | |
{ | |
struct elfhdr *elf; | |
struct proghdr *ph, *eph; | |
void (*entry)(void); | |
uchar* pa; | |
elf = (struct elfhdr*)0x10000; // scratch space | |
// Read 1st page off disk | |
readseg((uchar*)elf, 4096, 0); | |
// Is this an ELF executable? | |
// if(elf->magic != ELF_MAGIC) | |
// return; // let bootasm.S handle error | |
// Load each program segment (ignores ph flags). | |
ph = (struct proghdr*)((uchar*)elf + elf->phoff); | |
eph = ph + elf->phnum; | |
for(; ph < eph; ph++){ | |
pa = (uchar*)ph->paddr; | |
readseg(pa, ph->filesz, ph->off); | |
if(ph->memsz > ph->filesz) | |
stosb(pa + ph->filesz, 0, ph->memsz - ph->filesz); | |
} | |
// Call the entry point from the ELF header. | |
// Does not return! | |
entry = (void(*)(void))(elf->entry); | |
entry(); | |
} | |
void | |
waitdisk(void) | |
{ | |
// Wait for disk ready. | |
while((inb(0x1F7) & 0xC0) != 0x40) | |
; | |
} | |
// Read a single sector at offset into dst. | |
void | |
readsect(void *dst, uint offset) | |
{ | |
// Issue command. | |
waitdisk(); | |
outb(0x1F2, 1); // count = 1 | |
outb(0x1F3, offset); | |
outb(0x1F4, offset >> 8); | |
outb(0x1F5, offset >> 16); | |
outb(0x1F6, (offset >> 24) | 0xE0); | |
outb(0x1F7, 0x20); // cmd 0x20 - read sectors | |
// Read data. | |
waitdisk(); | |
insl(0x1F0, dst, SECTSIZE/4); | |
} | |
// Read 'count' bytes at 'offset' from kernel into physical address 'pa'. | |
// Might copy more than asked. | |
void | |
readseg(uchar* pa, uint count, uint offset) | |
{ | |
uchar* epa; | |
epa = pa + count; | |
// Round down to sector boundary. | |
pa -= offset % SECTSIZE; | |
// Translate from bytes to sectors; kernel starts at sector 1. | |
offset = (offset / SECTSIZE) + 1; | |
// If this is too slow, we could read lots of sectors at a time. | |
// We'd write more to memory than asked, but it doesn't matter -- | |
// we load in increasing order. | |
for(; pa < epa; pa += SECTSIZE, offset++) { | |
uint rem = (uint) pa; | |
uint divisor = 0x10000000; | |
for (; rem > 0; rem %= divisor, divisor /= 0x10) { | |
uchar c = (rem / divisor); | |
if (c > 9) { | |
c += 'A' - 10; | |
} else { | |
c += '0'; | |
} | |
outb(COM1, c); | |
} | |
// last char is probably just 0 | |
outb(COM1, '0'); | |
outb(COM1, 'h'); | |
outb(COM1, ' '); | |
if (((uint) pa & 0xFFF) == 0) { | |
outb(COM1, '\n'); | |
} | |
readsect(pa, offset); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment