first commit
This commit is contained in:
commit
3f556cba19
52
.gitignore
vendored
Normal file
52
.gitignore
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.elf
|
||||
|
||||
# Linker output
|
||||
*.ilk
|
||||
*.map
|
||||
*.exp
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
*.su
|
||||
*.idb
|
||||
*.pdb
|
||||
|
||||
# Kernel Module Compile Results
|
||||
*.mod*
|
||||
*.cmd
|
||||
.tmp_versions/
|
||||
modules.order
|
||||
Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
||||
15
Makefile
Normal file
15
Makefile
Normal file
@ -0,0 +1,15 @@
|
||||
BDIR = build
|
||||
SUBDIRS = biosboot boot mbr installboot installmbr
|
||||
|
||||
all: $(BDIR) $(SUBDIRS)
|
||||
|
||||
$(BDIR):
|
||||
mkdir -p $(BDIR)
|
||||
|
||||
clean: $(SUBDIRS)
|
||||
rm -rf $(BDIR)
|
||||
|
||||
$(SUBDIRS):
|
||||
@make -sC $@ $(MAKECMDGOALS) BDIR=$(PWD)/$(BDIR) IDIR=$(PWD)
|
||||
|
||||
.PHONY: biosboot boot installboot mbr installmbr
|
||||
12
Makefile.inc
Normal file
12
Makefile.inc
Normal file
@ -0,0 +1,12 @@
|
||||
LINKADDR = 0x40120
|
||||
LOADADDR = 0x40000
|
||||
BOOTMAGIC = 0xc001d00d
|
||||
BOOTREL = 0x60000
|
||||
|
||||
CC=cc
|
||||
CFLAGS=-m32 -Wall -Werror -march=i386 -O0 -fno-stack-protector -ffreestanding -fno-builtin
|
||||
CPPFLAGS=-nostdinc
|
||||
LD=ld
|
||||
AS=as
|
||||
ASFLAGS=-Wa,-O0,--32
|
||||
LDFLAGS=-melf_i386 -O0 -nostdlib -x -N -Bstatic -znorelro -no-pie
|
||||
18
biosboot/Makefile
Normal file
18
biosboot/Makefile
Normal file
@ -0,0 +1,18 @@
|
||||
include ../*.inc
|
||||
|
||||
PROG=biosboot
|
||||
SRCS=$(wildcard *.S)
|
||||
OBJS=$(SRCS:.S=.o)
|
||||
|
||||
CFLAGS+=-c -fno-pie
|
||||
LDFLAGS+=-Ttext 0 -T ld.script
|
||||
CPPFLAGS+=-nostdinc -DLOADADDR=$(LOADADDR) -DLINKADDR=$(LINKADDR) -DBOOTMAGIC=$(BOOTMAGIC)
|
||||
CPPFLAGS+=-I $(IDIR)
|
||||
|
||||
$(PROG): $(OBJS)
|
||||
$(LD) $(LDFLAGS) -o $(BDIR)/$(PROG) $(OBJS)
|
||||
|
||||
$(OBJS): ../def.h
|
||||
|
||||
clean:
|
||||
rm -f $(PROG) $(OBJS)
|
||||
203
biosboot/biosboot.S
Normal file
203
biosboot/biosboot.S
Normal file
@ -0,0 +1,203 @@
|
||||
.file "biosboot.S"
|
||||
|
||||
#include "def.h"
|
||||
|
||||
// 0x00000 -> 0x07BFF our stack (to 31k)
|
||||
// 0x07A00 -> 0x07BFF typical MBR loc (at 30k5)
|
||||
// 0x07C00 -> 0x07DFF our code biosboot (at 31k)
|
||||
// 0x07E00 -> ... /boot inode block (at 31k5)
|
||||
// 0x07E00 -> ... (indirect block if nec)
|
||||
// 0x40000 -> ... /boot (at 256k)
|
||||
|
||||
#define PBR_READ_ERROR 'R'
|
||||
#define PBR_CANT_BOOT 'X'
|
||||
#define PBR_BAD_MAGIC 'M'
|
||||
#define PBR_TOO_MANY_INDIRECTS 'I'
|
||||
#define CHAR_BLOCK_READ '.'
|
||||
#define putc(c) movb $c, %al; call Lchr
|
||||
#define puts(s) movw $s, %si; call Lmessage
|
||||
|
||||
.globl start_cluster, dst_seg_off
|
||||
.globl spc_sqrt, clu_off
|
||||
.globl part_offset, shift_magic, and_magic
|
||||
|
||||
.type start_cluster, @function
|
||||
.type dst_seg_off, @function
|
||||
.type spc_sqrt, @function
|
||||
.type clu_off, @function
|
||||
.type part_offset, @function
|
||||
.type shift_magic, @function
|
||||
.type and_magic, @function
|
||||
|
||||
.text
|
||||
.code16
|
||||
.globl _start
|
||||
|
||||
_start:
|
||||
jmp begin
|
||||
nop
|
||||
|
||||
. = _start + 0x1c
|
||||
ebpb: .long 16 /* hidden sectors */
|
||||
.long 0 /* large sectors */
|
||||
.word 0 /* physical disk */
|
||||
.byte 0x29 /* signature, needed by NT */
|
||||
.space 4, 0 /* volume serial number */
|
||||
.asciz "YO LABEL"
|
||||
.asciz "FAT 16"
|
||||
|
||||
|
||||
. = _start + 0x3e
|
||||
begin:
|
||||
ljmp $BOOTSEG, $main
|
||||
|
||||
cant_boot:
|
||||
movb $PBR_CANT_BOOT, %al
|
||||
jmp err_print_crlf
|
||||
|
||||
main:
|
||||
xorw %ax, %ax
|
||||
movw %ax, %ss
|
||||
movw $BOOTSTACKOFF, %sp
|
||||
|
||||
// data segment == code segment
|
||||
pushw %cs
|
||||
popw %ds
|
||||
movw $load_msg, %si
|
||||
call Lmessage
|
||||
testb $0x80, %dl
|
||||
jz cant_boot
|
||||
|
||||
load_boot:
|
||||
start_cluster = .+1
|
||||
movw $0x9090, %ax
|
||||
movw $LOADSEG, %bx // destination
|
||||
movw %bx, %di
|
||||
movw $FATSEG, %cx
|
||||
movw %cx, %es
|
||||
1:
|
||||
call read_cluster
|
||||
|
||||
read_fat:
|
||||
pushw %ax
|
||||
shift_magic = .+1
|
||||
movb $0x90, %cl
|
||||
shrw %cl, %ax
|
||||
addw %ds:0x0e, %ax
|
||||
movw $FATSEG, %bx
|
||||
call read_sector
|
||||
popw %cx
|
||||
and_magic = .+2
|
||||
andw $0x9090, %cx
|
||||
movw %es:(,%ecx, 2), %ax
|
||||
cmpw $0xFFF7, %ax
|
||||
jb 1b
|
||||
|
||||
jmp done_load
|
||||
|
||||
read_cluster:
|
||||
pushw %ax
|
||||
|
||||
spc_sqrt = .+2
|
||||
shlw $0x90, %ax
|
||||
clu_off = .+1
|
||||
addw $0x9090, %ax
|
||||
|
||||
movzb %ds:0x0d, %cx
|
||||
1:
|
||||
call read_sector
|
||||
incw %ax
|
||||
dst_seg_off = .+2
|
||||
addw $0x9090, %bx
|
||||
loop 1b
|
||||
|
||||
popw %ax
|
||||
ret
|
||||
|
||||
read_sector:
|
||||
pushw %ax
|
||||
movw %bx, lba_dst_seg
|
||||
part_offset = .+1
|
||||
addw $0x9090, %ax
|
||||
movl %eax, lba_src_low
|
||||
movw $lba_command, %si
|
||||
|
||||
do_int_13:
|
||||
movb $0x42, %ah
|
||||
int $0x13
|
||||
jc read_error
|
||||
|
||||
popw %ax
|
||||
ret
|
||||
|
||||
read_error:
|
||||
movb $PBR_READ_ERROR, %al
|
||||
err_print_crlf:
|
||||
movw $err_txt_crlf, %si
|
||||
jmp err_print2
|
||||
call stay_stopped
|
||||
Lmessage:
|
||||
cld
|
||||
1:
|
||||
lodsb
|
||||
orb %al, %al
|
||||
jz 1f
|
||||
call Lchr
|
||||
jmp 1b
|
||||
|
||||
Lchr:
|
||||
pushw %bx
|
||||
movb $0x0e, %ah
|
||||
xorw %bx, %bx
|
||||
incw %bx
|
||||
int $0x10
|
||||
popw %bx
|
||||
1:
|
||||
ret
|
||||
|
||||
done_load:
|
||||
movw $LOADSEG, %ax
|
||||
movw %ax, %es
|
||||
cmpl $ELFMAGIC, %es:0(,1)
|
||||
je exec_boot
|
||||
movb $PBR_BAD_MAGIC, %al
|
||||
|
||||
err_print:
|
||||
movw $err_txt, %si
|
||||
err_print2:
|
||||
movb %al, err_id
|
||||
err_stop:
|
||||
call Lmessage
|
||||
stay_stopped:
|
||||
sti
|
||||
hlt
|
||||
jmp stay_stopped
|
||||
|
||||
exec_boot:
|
||||
movzbl %dl, %eax
|
||||
pushl %eax
|
||||
pushl $BOOTMAGIC
|
||||
ljmp $(LINKADDR >> 4), $0
|
||||
|
||||
lba_command:
|
||||
.byte 0x10 /* size of command packet */
|
||||
.byte 0x00 /* reserved */
|
||||
lba_nread_sec:
|
||||
.word 0x01 // sectors to transfer max 127
|
||||
lba_dst_offset:
|
||||
.word 0x00 // target buffer offset
|
||||
lba_dst_seg:
|
||||
.word 0x00 // target buffer offset
|
||||
lba_src_low:
|
||||
.long 0x00
|
||||
lba_src_high:
|
||||
.long 0x00
|
||||
|
||||
load_msg: .asciz "Loading"
|
||||
err_txt_crlf: .ascii "\r\n"
|
||||
err_txt: .ascii "ERR "
|
||||
err_id: .ascii "?"
|
||||
crlf: .asciz "\r\n"
|
||||
|
||||
. = 0x200 - 2
|
||||
.word DOSMBR_SIGNATURE
|
||||
17
biosboot/ld.script
Normal file
17
biosboot/ld.script
Normal file
@ -0,0 +1,17 @@
|
||||
PHDRS
|
||||
{
|
||||
text PT_LOAD;
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text :
|
||||
{
|
||||
*(.text)
|
||||
} :text
|
||||
/DISCARD/ :
|
||||
{
|
||||
*(.note.gnu.property)
|
||||
*(.comment)
|
||||
}
|
||||
}
|
||||
17
boot/Makefile
Normal file
17
boot/Makefile
Normal file
@ -0,0 +1,17 @@
|
||||
include ../*.inc
|
||||
|
||||
PROG=boot
|
||||
CSRCS= $(wildcard *.c)
|
||||
SSRCS= $(wildcard *.S)
|
||||
OBJS = $(SSRCS:.S=.o) $(CSRCS:.c=.o)
|
||||
|
||||
CFLAGS+=-c -fno-pie
|
||||
CPPFLAGS+=-nostdinc -DLOADADDR=$(LOADADDR) -DLINKADDR=$(LINKADDR) -DBOOTMAGIC=$(BOOTMAGIC)
|
||||
LDFLAGS+= -s -T ld.script -Ttext=$(LINKADDR) --no-omagic
|
||||
|
||||
${PROG}: $(OBJS)
|
||||
@rm -f $(PROG)
|
||||
$(LD) $(LDFLAGS) -o $(BDIR)/$(PROG) $(OBJS)
|
||||
|
||||
clean:
|
||||
rm -f $(PROG) $(PROG).bin $(OBJS)
|
||||
56
boot/boot.c
Normal file
56
boot/boot.c
Normal file
@ -0,0 +1,56 @@
|
||||
typedef int dev_t;
|
||||
|
||||
#define SCREEN_WIDTH 80
|
||||
#define SCREEN_LENGTH 25
|
||||
#define VGA_BUFFER_ADDR 0xb8000
|
||||
|
||||
char*
|
||||
memcpy(char *a, char *b, int l)
|
||||
{
|
||||
for(int i = 0; i < l; ++i)
|
||||
a[i] = b[i];
|
||||
return a;
|
||||
}
|
||||
|
||||
int
|
||||
strlen(char *s)
|
||||
{
|
||||
int i = 0;
|
||||
for(; s[i]; ++i)
|
||||
;
|
||||
return i;
|
||||
}
|
||||
|
||||
char*
|
||||
itostr(int n, char *s)
|
||||
{
|
||||
char buf[16];
|
||||
char *p = buf;
|
||||
|
||||
do {
|
||||
*p++ = n%16;
|
||||
}while((n/=16) != 0);
|
||||
|
||||
while(p > buf){
|
||||
*s++ = "0123456789abcdef"[(int)*--p];
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
boot(dev_t bootdev)
|
||||
{
|
||||
char *p;
|
||||
char s[SCREEN_WIDTH] = "booted on disk:0x";
|
||||
short* vga = (short*)VGA_BUFFER_ADDR;
|
||||
|
||||
p = s+strlen(s);
|
||||
p = itostr((int)bootdev, p);
|
||||
for(int j = 0; j < SCREEN_LENGTH; ++j){
|
||||
for (int i = 0; i < sizeof(s); ++i) {
|
||||
vga[(j*SCREEN_WIDTH) + (i + SCREEN_WIDTH*2)] = 0x9100 | s[i];
|
||||
}
|
||||
}
|
||||
while(1)
|
||||
;
|
||||
}
|
||||
74
boot/gdt.S
Normal file
74
boot/gdt.S
Normal file
@ -0,0 +1,74 @@
|
||||
.file "gdt.S"
|
||||
|
||||
/* memory segment types */
|
||||
#define SDT_MEMRO 16 /* memory read only */
|
||||
#define SDT_MEMROA 17 /* memory read only accessed */
|
||||
#define SDT_MEMRW 18 /* memory read write */
|
||||
#define SDT_MEMRWA 19 /* memory read write accessed */
|
||||
#define SDT_MEMROD 20 /* memory read only expand dwn limit */
|
||||
#define SDT_MEMRODA 21 /* memory read only expand dwn limit accessed */
|
||||
#define SDT_MEMRWD 22 /* memory read write expand dwn limit */
|
||||
#define SDT_MEMRWDA 23 /* memory read write expand dwn limit acessed */
|
||||
#define SDT_MEME 24 /* memory execute only */
|
||||
#define SDT_MEMEA 25 /* memory execute only accessed */
|
||||
#define SDT_MEMER 26 /* memory execute read */
|
||||
#define SDT_MEMERA 27 /* memory execute read accessed */
|
||||
#define SDT_MEMEC 28 /* memory execute only conforming */
|
||||
#define SDT_MEMEAC 29 /* memory execute only accessed conforming */
|
||||
#define SDT_MEMERC 30 /* memory execute read conforming */
|
||||
#define SDT_MEMERAC 31 /* memory execute read accessed conforming */
|
||||
|
||||
#ifndef _ALIGN_TEXT
|
||||
# define _ALIGN_TEXT .align 2, 0x120
|
||||
#endif
|
||||
|
||||
/* NB == No Binding: use .globl or .weak as necessary */
|
||||
#define _ENTRY_NB(x) \
|
||||
.text; _ALIGN_TEXT; .type x,@function; x:
|
||||
#define _ENTRY(x) .globl x; _ENTRY_NB(x)
|
||||
|
||||
|
||||
.text
|
||||
.code32
|
||||
|
||||
.align 8
|
||||
gdt:
|
||||
/* 0x00 : null */
|
||||
.space 8
|
||||
/* 0x08 : flat code */
|
||||
.word 0xFFFF # lolimit
|
||||
.word 0 # lobase
|
||||
.byte 0 # midbase
|
||||
.byte SDT_MEMERAC | 0 | 0x80 # RXAC, dpl = 0, present
|
||||
.byte 0xf | 0 | 0x40 | 0x80 # hilimit, xx, 32bit, 4k granularity
|
||||
.byte 0 # hibase
|
||||
/* 0x10 : flat data */
|
||||
.word 0xFFFF # lolimit
|
||||
.word 0 # lobase
|
||||
.byte 0 # midbase
|
||||
.byte SDT_MEMRWA | 0 | 0x80 # RWA, dpl = 0, present
|
||||
.byte 0xf | 0 | 0x40 | 0x80 # hilimit, xx, 32bit, 4k granularity
|
||||
.byte 0 # hibase
|
||||
/* 0x18 : 16 bit code */
|
||||
.word 0xFFFF # lolimit
|
||||
.word (LINKADDR & 0xffff) # lobase
|
||||
.byte (LINKADDR >> 16) & 0xff # midbase
|
||||
.byte SDT_MEMERAC | 0 | 0x80 # RXAC, dpl = 0, present
|
||||
.byte 0x0 | 0 | 0 | 0 # hilimit, xx, 16bit, byte granularity
|
||||
.byte (LINKADDR >> 20) & 0xff # hibase
|
||||
/* 0x20 : 16 bit data */
|
||||
.word 0xFFFF # lolimit
|
||||
.word (LINKADDR & 0xffff) # lobase
|
||||
.byte (LINKADDR >> 16) & 0xff # midbase
|
||||
.byte SDT_MEMRWA | 0 | 0x80 # RWA, dpl = 0, present
|
||||
.byte 0x0 | 0 | 0 | 0 # hilimit, xx, 16bit, byte granularity
|
||||
.byte (LINKADDR >> 20) & 0xff # hibase
|
||||
|
||||
|
||||
.globl Gdtr
|
||||
Gdtr:
|
||||
.word . - gdt -1
|
||||
.long gdt
|
||||
.word 0
|
||||
|
||||
.end
|
||||
26
boot/ld.script
Normal file
26
boot/ld.script
Normal file
@ -0,0 +1,26 @@
|
||||
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
||||
OUTPUT_ARCH(i386)
|
||||
|
||||
PHDRS
|
||||
{
|
||||
text PT_LOAD;
|
||||
}
|
||||
SECTIONS
|
||||
{
|
||||
.text : {
|
||||
KEEP(srt0.o(.text))
|
||||
*(.text)
|
||||
} :text
|
||||
etext = .;
|
||||
.data : { *(.data) } :text
|
||||
edata = .;
|
||||
.bss : { *(.bss) } :text
|
||||
ebss = .;
|
||||
end = .;
|
||||
/DISCARD/ :
|
||||
{
|
||||
*(.note.gnu.property)
|
||||
*(.comment)
|
||||
}
|
||||
}
|
||||
|
||||
47
boot/srt0.S
Normal file
47
boot/srt0.S
Normal file
@ -0,0 +1,47 @@
|
||||
.file "srt0.S"
|
||||
|
||||
#define BOOTSTACK 0xfffc
|
||||
#define CR0_PE 0x00000001 /* Protected mode Enable */
|
||||
|
||||
.globl end
|
||||
.globl edata
|
||||
.globl Gdtr
|
||||
.globl boot
|
||||
|
||||
.text
|
||||
.code16
|
||||
.align 16
|
||||
.globl _start
|
||||
_start:
|
||||
popl %eax
|
||||
cmpl $BOOTMAGIC, %eax
|
||||
je 1f
|
||||
|
||||
1:
|
||||
popl %edx
|
||||
cli
|
||||
pushl %cs
|
||||
popl %ds
|
||||
addr32 data32 lgdt (Gdtr - LINKADDR)
|
||||
movl %cr0, %eax
|
||||
orl $CR0_PE, %eax
|
||||
data32 movl %eax, %cr0
|
||||
data32 ljmp $8, $1f
|
||||
|
||||
1:
|
||||
.code32
|
||||
movl $0x10, %eax
|
||||
mov %ax, %ds
|
||||
mov %ax, %ss
|
||||
mov %ax, %es
|
||||
mov %ax, %fs
|
||||
mov %ax, %gs
|
||||
movl $BOOTSTACK, %esp
|
||||
pushl %edx
|
||||
|
||||
|
||||
// fill 0 .bss
|
||||
xorl %eax, %eax
|
||||
|
||||
call boot;
|
||||
|
||||
96
dat.h
Normal file
96
dat.h
Normal file
@ -0,0 +1,96 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
#include "def.h"
|
||||
|
||||
#define elem(x) ((int)(sizeof(x)/sizeof((x)[0])))
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
typedef unsigned int uint;
|
||||
|
||||
typedef struct{
|
||||
u64 cyl;
|
||||
u64 head;
|
||||
u64 sec;
|
||||
}CHS;
|
||||
|
||||
typedef struct{
|
||||
u8 flag; /* bootstrap flags */
|
||||
u8 bhd; /* begin head */
|
||||
u8 bsec; /* begin sector */
|
||||
u8 bcyl; /* begin cylinder */
|
||||
u8 type; /* partition type (see below) */
|
||||
u8 ehd; /* end head */
|
||||
u8 esec; /* end sec2r */
|
||||
u8 ecyl; /* end cylinder */
|
||||
u32 beg; /* absolute starting sectoff number */
|
||||
u32 size; /* partition size in sec2rs */
|
||||
} __attribute__((packed)) DOSpart;
|
||||
|
||||
typedef struct{
|
||||
u8 boot[DOSPARTOFF];
|
||||
DOSpart parts[NDOSPART];
|
||||
u16 sign;
|
||||
} __attribute__((packed)) DOSmbr;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u64 bs, ns;
|
||||
u8 flag, id;
|
||||
}Part;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DOSpart parts[NDOSPART];
|
||||
u32 bps; // byte per sector
|
||||
u32 spt; // sector per track
|
||||
u32 hpc; // header per cylinder
|
||||
u32 nsec; // number of sectors;
|
||||
u32 type; // major minor;
|
||||
int fd;
|
||||
char *name;
|
||||
}Disk;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 ext;
|
||||
u32 self;
|
||||
u8 code[DOSPARTOFF];
|
||||
Part parts[NDOSPART];
|
||||
u16 sign;
|
||||
u16 zeros;
|
||||
}MBR;
|
||||
|
||||
static Disk
|
||||
diskopen(char *name, int flag)
|
||||
{
|
||||
char buf[512];
|
||||
u64 nsec;
|
||||
struct stat st;
|
||||
Disk d = {.bps=512, .spt=63, .hpc=255,};
|
||||
|
||||
d.name = name;
|
||||
assert((d.fd = open(d.name, flag)) != -1);
|
||||
assert(fstat(d.fd, &st) != -1);
|
||||
if(S_ISBLK(st.st_mode))
|
||||
assert(ioctl(d.fd, BLKGETSIZE, &nsec) != -1);
|
||||
else if(S_ISREG(st.st_mode))
|
||||
nsec = st.st_size/d.bps;
|
||||
else
|
||||
assert(0);
|
||||
|
||||
d.nsec = nsec < FAT16_MAX ? nsec : FAT16_MAX;
|
||||
assert(sizeof(buf) == read(d.fd, buf, sizeof(buf)));
|
||||
memcpy(d.parts, buf+DOSPARTOFF, sizeof(d.parts));
|
||||
assert(lseek(d.fd, 0, SEEK_SET) == 0);
|
||||
|
||||
return d;
|
||||
}
|
||||
22
def.h
Normal file
22
def.h
Normal file
@ -0,0 +1,22 @@
|
||||
#define FAT16_MAX (0x40000)
|
||||
#define DOSPTYP_UNUSED 0x00
|
||||
#define DOSPTYP_FAT16 0x06
|
||||
#define DOSPARTOFF 446
|
||||
#define DOSDISKOFF 444
|
||||
#define NDOSPART 4
|
||||
#define DOSACTIVE 0x80
|
||||
#define DOSMBR_SIGNATURE 0xAA55
|
||||
#define BOOT_MAGIC 0xf1abde3f
|
||||
#define DOSMBR_SIGNATURE_OFF 0x1fe
|
||||
|
||||
#define BOOTSEG 0x7c0
|
||||
#define BOOTRELOCSEG 0x7a0
|
||||
#define MBRSTACKOFF 0xfffc
|
||||
#define PARTSZ 16
|
||||
#define LOADSEG (LOADADDR >> 4)
|
||||
#define FATSEG 0x07e0 /* FAT table segment */
|
||||
|
||||
#define BOOTSTACKOFF ((BOOTSEG << 4) - 4) /* stack starts here, grows down */
|
||||
#define LFMAGIC 0x464c /* LFMAGIC (last two bytes of \7fELF) */
|
||||
#define ELFMAGIC 0x464c457f /* ELFMAGIC ("\7fELF") */
|
||||
|
||||
18
install.sh
Executable file
18
install.sh
Executable file
@ -0,0 +1,18 @@
|
||||
#!/bin/sh
|
||||
|
||||
S=$(pwd)/build
|
||||
img=$1
|
||||
|
||||
set -e
|
||||
|
||||
make
|
||||
|
||||
if [ -z ${1} ]
|
||||
then
|
||||
img=$S/img
|
||||
rm -rf $img
|
||||
dd if=/dev/zero of=$img bs=512 count=262144
|
||||
fi
|
||||
|
||||
sudo ${S}/installmbr $img
|
||||
sudo ${S}/installboot $img
|
||||
15
installboot/Makefile
Normal file
15
installboot/Makefile
Normal file
@ -0,0 +1,15 @@
|
||||
PROG=installboot
|
||||
SRCS=$(wildcard *.c)
|
||||
OBJS=$(SRCS:.c=.o)
|
||||
|
||||
CFLAGS = -g -Wall -Werror
|
||||
CPPFLAGS = -I $(IDIR)
|
||||
|
||||
${PROG}: $(OBJS)
|
||||
$(CC) $(CFLAGS) -o $(BDIR)/$(PROG) $^
|
||||
cp filecopy.sh $(BDIR)
|
||||
|
||||
$(OBJS): ../dat.h
|
||||
|
||||
clean:
|
||||
rm -rf $(PROG) *.o
|
||||
65
installboot/elf32.h
Normal file
65
installboot/elf32.h
Normal file
@ -0,0 +1,65 @@
|
||||
#include <elf.h>
|
||||
|
||||
/* e_ident */
|
||||
#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
|
||||
(ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
|
||||
(ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
|
||||
(ehdr).e_ident[EI_MAG3] == ELFMAG3)
|
||||
|
||||
typedef Elf32_Ehdr Ehdr;
|
||||
typedef Elf32_Phdr Ephdr;
|
||||
typedef Elf32_Shdr Eshdr;
|
||||
typedef Elf32_Sym Esym;
|
||||
|
||||
static Ehdr
|
||||
readEhdr(int fd)
|
||||
{
|
||||
Ehdr h;
|
||||
|
||||
assert(pread(fd, &h, sizeof(h), 0) == h.e_ehsize);
|
||||
assert(IS_ELF(h) == 1);
|
||||
return h;
|
||||
}
|
||||
|
||||
static Ephdr
|
||||
readEphdr(int fd, Ehdr h, int i)
|
||||
{
|
||||
Ephdr ph;
|
||||
int off;
|
||||
|
||||
off = h.e_phoff+i*h.e_phentsize;
|
||||
assert(pread(fd, &ph, h.e_phentsize, off)
|
||||
== sizeof(Ephdr));
|
||||
return ph;
|
||||
}
|
||||
|
||||
static Eshdr
|
||||
readEshdr(int fd, Ehdr h, int i)
|
||||
{
|
||||
Eshdr sh;
|
||||
int off;
|
||||
|
||||
off = h.e_shoff + i*h.e_shentsize;
|
||||
assert(pread(fd, &sh, h.e_shentsize, off) == sizeof(sh));
|
||||
return sh;
|
||||
}
|
||||
|
||||
static void*
|
||||
readEcode(int fd, Ehdr h, Ephdr ph, void *dst)
|
||||
{
|
||||
if(dst == NULL)
|
||||
assert((dst = calloc(1, ph.p_filesz)) != NULL);
|
||||
assert(pread(fd, dst, ph.p_filesz, ph.p_offset) ==
|
||||
ph.p_filesz);
|
||||
return dst;
|
||||
}
|
||||
|
||||
static void*
|
||||
readsymtab(int fd, Eshdr sh, void *dst)
|
||||
{
|
||||
if(dst == NULL)
|
||||
assert((dst = calloc(1, sh.sh_size)) != NULL);
|
||||
assert(pread(fd, dst, sh.sh_size, sh.sh_offset)
|
||||
== sh.sh_size);
|
||||
return dst;
|
||||
}
|
||||
34
installboot/filecopy.sh
Executable file
34
installboot/filecopy.sh
Executable file
@ -0,0 +1,34 @@
|
||||
#!/bin/sh
|
||||
|
||||
abort()
|
||||
{
|
||||
umount $dir 2>/dev/null
|
||||
rm -rf $dir
|
||||
echo >&2 "fail to install"
|
||||
exit 0
|
||||
}
|
||||
|
||||
trap 'abort' 0
|
||||
set -eu
|
||||
|
||||
dir=$(mktemp -d)
|
||||
nsec=$((($(blockdev --getsz $1) - 64)/2))
|
||||
|
||||
if [ ${nsec} -ge $((16*1024)) ]
|
||||
then
|
||||
nsec=$((16*1024-64/2))
|
||||
fi
|
||||
|
||||
mkfs.fat -F16 -R 1 -r 512 -a -I --offset 64 $1 $nsec
|
||||
|
||||
mount -o offset=$((512*64)) $1 $dir
|
||||
|
||||
mkdir -p $dir/root
|
||||
|
||||
cp -f build/boot $dir/root/boot
|
||||
|
||||
trap - 0
|
||||
umount $dir >&2
|
||||
rm -rf $dir
|
||||
sync
|
||||
exit 1
|
||||
244
installboot/installboot.c
Normal file
244
installboot/installboot.c
Normal file
@ -0,0 +1,244 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/wait.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include "dat.h"
|
||||
#include "elf32.h"
|
||||
|
||||
static char *devpath;
|
||||
static char *stage1 = "build/biosboot";
|
||||
static char *shpath = "build/filecopy.sh";
|
||||
static Disk dsk;
|
||||
static int btpart;
|
||||
static char btcode[512];
|
||||
|
||||
// need patch
|
||||
static struct{
|
||||
char *name;
|
||||
u32 size;
|
||||
u32 addr;
|
||||
union{
|
||||
u32 val;
|
||||
struct{
|
||||
u16 low;
|
||||
u16 high;
|
||||
};
|
||||
u8 byte;
|
||||
};
|
||||
}syms[] = {
|
||||
{"start_cluster", 2},
|
||||
{"dst_seg_off", 2},
|
||||
{"spc_sqrt", 1},
|
||||
{"clu_off", 2},
|
||||
{"part_offset", 2},
|
||||
{"shift_magic", 1},
|
||||
{"and_magic", 2},
|
||||
};
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, "usgae: ./installboot device [bin]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
streq(char *a, char *b)
|
||||
{
|
||||
int la = strlen(a);
|
||||
return la==strlen(b) && memcmp(a, b, la)==0;
|
||||
}
|
||||
|
||||
void
|
||||
loadelf(char *fname)
|
||||
{
|
||||
int fd;
|
||||
char *tbbeg, *tbstr;
|
||||
Ehdr h;
|
||||
Ephdr ph;
|
||||
Eshdr shsym, shstr;
|
||||
Esym *tbsym;
|
||||
|
||||
assert((fd = open(fname, O_RDONLY))!=-1);
|
||||
h = readEhdr(fd);
|
||||
assert(h.e_phnum == 1); // only 1 program header
|
||||
assert(h.e_shnum >= 2);
|
||||
ph = readEphdr(fd, h, 0);
|
||||
assert(ph.p_filesz == sizeof(btcode));
|
||||
|
||||
for(int i = 0; i < h.e_shnum; ++i)
|
||||
if((shsym = readEshdr(fd, h, i)).sh_type == SHT_SYMTAB)
|
||||
goto found;
|
||||
assert(0 && "Can't find shymbol table\n");
|
||||
|
||||
found:
|
||||
shstr = readEshdr(fd, h, shsym.sh_link);
|
||||
assert(shstr.sh_type == SHT_STRTAB);
|
||||
assert((tbbeg = calloc(1, shstr.sh_size + shsym.sh_size))!=NULL);
|
||||
tbstr = readsymtab(fd, shstr, tbbeg);
|
||||
tbsym = readsymtab(fd, shsym, tbbeg+shstr.sh_size);
|
||||
|
||||
for(int i = 0; i < elem(syms); ++i){
|
||||
for(int j = 0; j < shsym.sh_size/sizeof(*tbsym); ++j)
|
||||
if(streq(syms[i].name, tbstr + tbsym[j].st_name)){
|
||||
syms[i].addr = tbsym[j].st_value;
|
||||
break;
|
||||
}
|
||||
assert(syms[i].addr != 0&& "Can't find symbol in symtab\n");
|
||||
}
|
||||
|
||||
readEcode(fd, h, ph, btcode);
|
||||
free(tbbeg);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void
|
||||
symset(char *name, u32 val)
|
||||
{
|
||||
for(int i = 0; i < elem(syms); ++i){
|
||||
if(streq(name, syms[i].name)){
|
||||
syms[i].val = val;
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert(0 && "symbol not exist");
|
||||
}
|
||||
|
||||
uint
|
||||
tou32(u8 *str, int i)
|
||||
{
|
||||
uint x = 0;
|
||||
|
||||
do{
|
||||
x = x << 8;
|
||||
x |= str[--i];
|
||||
}while(i > 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
u16
|
||||
exponent(u16 x)
|
||||
{
|
||||
switch(x){
|
||||
case 1: return 0;
|
||||
case 2: return 1;
|
||||
case 4: return 2;
|
||||
case 8: return 4;
|
||||
case 16: return 8;
|
||||
case 32: return 16;
|
||||
case 512: return 9;
|
||||
case 1024: return 10;
|
||||
case 2048: return 11;
|
||||
case 4096: return 12;
|
||||
default: assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
emit(u64 off)
|
||||
{
|
||||
for(int i = 0; i < elem(syms); ++i){
|
||||
switch(syms[i].size){
|
||||
case 1:
|
||||
btcode[syms[i].addr] = syms[i].byte;
|
||||
break;
|
||||
case 2:
|
||||
*(u16*)&btcode[syms[i].addr] = syms[i].low;
|
||||
break;
|
||||
case 4:
|
||||
*(u32*)&btcode[syms[i].addr] = syms[i].val;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
assert(pwrite(dsk.fd, btcode+0x3c, sizeof(btcode)-0x3c, off+0x3c) ==
|
||||
sizeof(btcode)-0x3c);
|
||||
}
|
||||
|
||||
void
|
||||
setbootparam(int ino, int off, int sec)
|
||||
{
|
||||
u8 buf[512];
|
||||
u16 rdsecsz, dasec;
|
||||
|
||||
assert(sizeof(buf) == pread(dsk.fd, buf, sizeof(buf), off));
|
||||
|
||||
u32 bps = tou32(buf+0x0b, 2);
|
||||
u32 spc = tou32(buf+0x0d, 1);
|
||||
u32 res = tou32(buf+0x0e, 2);
|
||||
u32 nfat = tou32(buf+0x10, 1);
|
||||
u32 nrde = tou32(buf+0x11, 2);
|
||||
// u32 nsec = tou32(buf+0x13, 2);
|
||||
u32 nspf = tou32(buf+0x16, 2); // numberof sector per fat16
|
||||
rdsecsz = (nrde*32 + (bps - 1))/bps;
|
||||
dasec = res + (nspf*nfat) + rdsecsz;
|
||||
assert(0xaa55 == tou32(buf+0x1fe, 2));
|
||||
|
||||
symset("dst_seg_off", bps>>4);
|
||||
symset("start_cluster", ino);
|
||||
symset("spc_sqrt", exponent(spc));
|
||||
symset("clu_off", dasec - 2 * spc);
|
||||
symset("part_offset", sec);
|
||||
symset("shift_magic", exponent(bps)-3);
|
||||
symset("and_magic", bps-1);
|
||||
}
|
||||
|
||||
void
|
||||
catpath(char *dst, char *s1, char *s2)
|
||||
{
|
||||
while(*s1)
|
||||
*dst++ = *s1++;
|
||||
*dst++ = '/';
|
||||
while(*s2)
|
||||
*dst++ = *s2++;
|
||||
*dst = '\0';
|
||||
}
|
||||
|
||||
void
|
||||
install(void)
|
||||
{
|
||||
char *args[] = {shpath, devpath, NULL};
|
||||
pid_t pid;
|
||||
u64 beg;
|
||||
|
||||
switch(pid = fork()){
|
||||
default:
|
||||
assert(wait(NULL) == pid);
|
||||
sync();
|
||||
break;
|
||||
case 0:
|
||||
assert(execvp(args[0], args) != -1);
|
||||
case -1:
|
||||
assert(0);
|
||||
}
|
||||
dsk = diskopen(devpath, O_RDWR);
|
||||
for(int i = 0; i < elem(dsk.parts); ++i)
|
||||
if(dsk.parts[i].type == DOSPTYP_FAT16 && dsk.parts[i].flag == DOSACTIVE){
|
||||
btpart = i;
|
||||
goto found;
|
||||
}
|
||||
assert(0);
|
||||
|
||||
found:
|
||||
beg = dsk.parts[btpart].beg * dsk.bps;
|
||||
setbootparam(4, beg, dsk.parts[btpart].beg);
|
||||
emit(beg);
|
||||
close(dsk.fd);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
if(argc < 2 || argc > 3)
|
||||
usage();
|
||||
devpath = argv[1];
|
||||
loadelf(stage1);
|
||||
install();
|
||||
return 0;
|
||||
}
|
||||
15
installmbr/Makefile
Normal file
15
installmbr/Makefile
Normal file
@ -0,0 +1,15 @@
|
||||
PROG=installmbr
|
||||
SRCS=$(wildcard *.c)
|
||||
OBJS=$(SRCS:.c=.o)
|
||||
|
||||
CFLAGS = -g
|
||||
CPPFLAGS = -I $(IDIR)
|
||||
|
||||
${PROG}: $(OBJS)
|
||||
@rm -f $(PROG)
|
||||
$(CC) $(CFLAGS) -o $(BDIR)/$(PROG) $^
|
||||
|
||||
$(OBJS): ../dat.h
|
||||
|
||||
clean:
|
||||
rm -rf $(PROG) $(OBJS)
|
||||
238
installmbr/installmbr.c
Normal file
238
installmbr/installmbr.c
Normal file
@ -0,0 +1,238 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/fs.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <endian.h>
|
||||
#include <stdlib.h>
|
||||
#include "dat.h"
|
||||
|
||||
static char *binpath = "build/mbr";
|
||||
static char bootcode[DOSPARTOFF];
|
||||
static Disk dsk;
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: ./mkmbr device\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int
|
||||
secwrite(void *buf, u64 sec, u32 cnt, Disk *dsk)
|
||||
{
|
||||
ssize_t wc;
|
||||
off_t off;
|
||||
ssize_t n = cnt * dsk->bps;
|
||||
off_t where = sec * dsk->bps;
|
||||
|
||||
off = lseek(dsk->fd, where, SEEK_SET);
|
||||
assert(off != -1);
|
||||
wc = write(dsk->fd, buf, n);
|
||||
assert(wc != -1);
|
||||
assert(wc == n);
|
||||
return wc;
|
||||
}
|
||||
|
||||
char*
|
||||
secread(u64 sec, u32 cnt, Disk *dsk)
|
||||
{
|
||||
char *buf;
|
||||
ssize_t rc;
|
||||
off_t off;
|
||||
ssize_t n = cnt * dsk->bps;
|
||||
off_t where = sec * dsk->bps;
|
||||
|
||||
off = lseek(dsk->fd, where, SEEK_SET);
|
||||
assert(off != -1);
|
||||
buf = calloc(1, n);
|
||||
assert(buf != NULL);
|
||||
rc = read(dsk->fd, buf, n);
|
||||
assert(rc != -1);
|
||||
assert(rc == n);
|
||||
return buf;
|
||||
}
|
||||
|
||||
int
|
||||
diskwrite(void *buf, u64 sec, u64 sz, Disk *dsk)
|
||||
{
|
||||
char *secbuf;
|
||||
u32 cnt;
|
||||
int wc;
|
||||
|
||||
cnt = (sz + dsk->bps - 1) / dsk->bps;
|
||||
secbuf = secread(sec, cnt, dsk);
|
||||
memcpy(secbuf, buf, sz);
|
||||
wc = secwrite(secbuf, sec, cnt, dsk);
|
||||
free(secbuf);
|
||||
return wc;
|
||||
}
|
||||
|
||||
Part
|
||||
dospt2pt(DOSpart dpt, u64 self, u64 ext)
|
||||
{
|
||||
Part pt={0,};
|
||||
off_t off;
|
||||
u32 t;
|
||||
|
||||
assert(dpt.type != DOSPTYP_FAT16);
|
||||
pt.flag = dpt.flag;
|
||||
pt.id = dpt.type;
|
||||
off = self;
|
||||
memcpy(&t, &dpt.beg, sizeof(u32));
|
||||
pt.bs = htole32(t) + off;
|
||||
memcpy(&t, &dpt.size, sizeof(u32));
|
||||
pt.ns = htole32(t);
|
||||
return pt;
|
||||
}
|
||||
|
||||
// C = LBA / (HPC * SPT)
|
||||
// H = (LBA / SPT) % HPC
|
||||
// S = (LBA / SPT) + 1
|
||||
|
||||
CHS
|
||||
lba2chs(u64 lba, u64 spt, u64 hpc)
|
||||
{
|
||||
CHS c = {0,};
|
||||
|
||||
c.cyl = lba / (spt * hpc);
|
||||
c.head = (lba / spt) % hpc;
|
||||
c.sec = (lba % spt) + 1;
|
||||
return c;
|
||||
}
|
||||
|
||||
CHS
|
||||
lba2chsbeg(Part pt)
|
||||
{
|
||||
if(pt.ns == 0 || pt.id == DOSPTYP_UNUSED)
|
||||
return (CHS){0,};
|
||||
return lba2chs(pt.bs, dsk.spt, dsk.hpc);
|
||||
}
|
||||
|
||||
CHS
|
||||
lba2chsend(Part pt)
|
||||
{
|
||||
if(pt.ns == 0 || pt.id == DOSPTYP_UNUSED)
|
||||
return (CHS){0,};
|
||||
return lba2chs(pt.bs+pt.ns-1, dsk.spt, dsk.hpc);
|
||||
}
|
||||
|
||||
CHS
|
||||
chsnorm(u8 id, CHS c)
|
||||
{
|
||||
if(c.head > 254 || c.sec > 63 || c.cyl > 1023){
|
||||
c.head = 254;
|
||||
c.sec = 63;
|
||||
c.cyl = 1023;
|
||||
}
|
||||
c.head = c.head & 0xFF;
|
||||
c.sec = (c.sec & 0x3F) | ((c.cyl & 0x300) >> 2);
|
||||
c.cyl = c.cyl & 0xFF;
|
||||
return c;
|
||||
}
|
||||
|
||||
DOSpart
|
||||
pt2dospt(Part pt, u64 self, u64 ext)
|
||||
{
|
||||
DOSpart d={0,};
|
||||
CHS c;
|
||||
u64 off, t;
|
||||
|
||||
if(pt.ns == 0 || pt.id == DOSPTYP_UNUSED)
|
||||
return d;
|
||||
off = self;
|
||||
c = chsnorm(pt.id, lba2chsbeg(pt));
|
||||
d.bcyl = c.cyl;
|
||||
d.bhd = c.head;
|
||||
d.bsec = c.sec;
|
||||
c = chsnorm(pt.id, lba2chsend(pt));
|
||||
d.ecyl = c.cyl;
|
||||
d.ehd = c.head;
|
||||
d.esec = c.sec;
|
||||
d.flag = pt.flag & 0xff;
|
||||
d.type = pt.id & 0xff;
|
||||
t = pt.bs - off;
|
||||
memcpy(&d.beg, &t, sizeof(d.beg));
|
||||
t = htole64(pt.ns);
|
||||
memcpy(&d.size, &t, sizeof(d.size));
|
||||
return d;
|
||||
}
|
||||
|
||||
DOSmbr
|
||||
mbr2dosmbr(MBR m)
|
||||
{
|
||||
DOSmbr d={0,};
|
||||
|
||||
memcpy(d.boot, m.code, sizeof(m.code));
|
||||
d.sign = htole16(DOSMBR_SIGNATURE);
|
||||
for(int i = 0; i < elem(d.parts); ++i){
|
||||
DOSpart dpt = {0,};
|
||||
if(i < elem(m.parts))
|
||||
dpt = pt2dospt(m.parts[i], m.self, m.ext);
|
||||
d.parts[i] = dpt;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
MBR
|
||||
mbrinit(void)
|
||||
{
|
||||
MBR m = {0,};
|
||||
DOSpart dpt={0,};
|
||||
Part bpt={0,}, mpt={0,};
|
||||
u32 i;
|
||||
|
||||
bpt = dospt2pt(dpt, 0, 0);
|
||||
i = 1;
|
||||
while(i < dsk.spt)
|
||||
i *= 2;
|
||||
mpt.bs = i;
|
||||
mpt.ns = dsk.nsec - mpt.bs;
|
||||
mpt.id = DOSPTYP_FAT16;
|
||||
mpt.flag = DOSACTIVE;
|
||||
|
||||
memcpy(m.code, bootcode, sizeof(bootcode));
|
||||
m.parts[0] = bpt;
|
||||
m.parts[3] = mpt;
|
||||
m.sign = DOSMBR_SIGNATURE;
|
||||
return m;
|
||||
}
|
||||
|
||||
int
|
||||
mbrwrite(MBR m)
|
||||
{
|
||||
DOSmbr d;
|
||||
int wc;
|
||||
|
||||
d = mbr2dosmbr(m);
|
||||
wc = diskwrite(&d, m.self, sizeof(d), &dsk);
|
||||
return wc;
|
||||
}
|
||||
|
||||
void
|
||||
read512(char *path)
|
||||
{
|
||||
int fd;
|
||||
ssize_t rc;
|
||||
|
||||
assert((fd = open(path, O_RDONLY)) != -1);
|
||||
rc = read(fd, bootcode, sizeof(bootcode));
|
||||
assert(rc == sizeof(bootcode));
|
||||
close(fd);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
MBR m;
|
||||
char buf[1024];
|
||||
|
||||
printf("%s\n", getcwd(buf, sizeof(buf)));
|
||||
if(argc < 2)
|
||||
usage();
|
||||
read512(binpath);
|
||||
dsk = diskopen(argv[1], O_RDWR);
|
||||
m = mbrinit();
|
||||
printf("write %dbyte to %s\n", mbrwrite(m), dsk.name);
|
||||
return 0;
|
||||
}
|
||||
19
mbr/Makefile
Normal file
19
mbr/Makefile
Normal file
@ -0,0 +1,19 @@
|
||||
PROG=mbr
|
||||
SRCS=$(wildcard *.S)
|
||||
OBJS=$(SRCS:.S=.o)
|
||||
|
||||
LDFLAGS = -Ttext 0 -e 0
|
||||
CPPFLAGS = -I $(IDIR)
|
||||
|
||||
${PROG}: $(OBJS)
|
||||
@rm -f $(PROG)
|
||||
$(LD) $(LDFLAGS) -o $(PROG) $(OBJS)
|
||||
objcopy -O binary mbr mbr.new
|
||||
dd if=mbr.new of=mbr bs=512 count=1
|
||||
rm -rf mbr.new
|
||||
mv $(PROG) $(BDIR)
|
||||
|
||||
$(OBJS): ../def.h
|
||||
|
||||
clean:
|
||||
rm -f *.o *.bin $(PROG)
|
||||
193
mbr/mbr.S
Normal file
193
mbr/mbr.S
Normal file
@ -0,0 +1,193 @@
|
||||
.file "mbr.S"
|
||||
|
||||
#include "def.h"
|
||||
|
||||
#define CHAR_LBA_READ '.'
|
||||
#define CHAR_R 'R'
|
||||
#define CHAR_S 'S'
|
||||
#define CHAR_L 'L'
|
||||
#define CHAR_B 'B'
|
||||
#define CHAR_G 'G'
|
||||
#define DBGMSG(c) movb $c, %al; call Lchr
|
||||
#define puts(s) movw $s, %si; call Lmessage
|
||||
|
||||
// 0x07C00 - 0x07DFF BIOS load us here
|
||||
// 0x07E00 - 0x17BFC using stack
|
||||
// 0x07A00 - 0x07BFF relocate to here
|
||||
// 0x07C00 - 0x07DFF load PBR here
|
||||
|
||||
.text
|
||||
.code16
|
||||
.globl start
|
||||
|
||||
start:
|
||||
// Adjust %cs to be right
|
||||
ljmp $BOOTSEG, $1f
|
||||
1:
|
||||
// set up stack
|
||||
movw %cs, %ax
|
||||
// cli
|
||||
movw %ax, %ss
|
||||
movw $MBRSTACKOFF, %sp
|
||||
|
||||
// set up data segment
|
||||
movw %ax, %ds
|
||||
DBGMSG(CHAR_S)
|
||||
|
||||
// relocate for PBR
|
||||
// copy to 0x07a0
|
||||
movw $BOOTRELOCSEG, %ax
|
||||
movw %ax, %es
|
||||
xorw %si, %si
|
||||
xorw %di, %di
|
||||
movw $0x200, %cx // Move (E)CX words from DS:[(E)SI] to ES:[(E)DI]
|
||||
cld
|
||||
rep movsb
|
||||
|
||||
// jump to relocated self
|
||||
ljmp $BOOTRELOCSEG, $reloc
|
||||
|
||||
reloc:
|
||||
DBGMSG(CHAR_R)
|
||||
|
||||
pushw %ds
|
||||
popw %es
|
||||
pushw %cs
|
||||
popw %ds
|
||||
testb $DOSACTIVE, %dl
|
||||
jnz drive_ok
|
||||
puts(efdmbr)
|
||||
jmp stay_stopped
|
||||
|
||||
drive_ok:
|
||||
movw $pt, %si
|
||||
movw $NDOSPART, %cx
|
||||
|
||||
find_active:
|
||||
DBGMSG(CHAR_L)
|
||||
movb (%si), %al
|
||||
cmpb $DOSACTIVE, %al
|
||||
je found
|
||||
addw $PARTSZ, %si
|
||||
loop find_active
|
||||
|
||||
no_part:
|
||||
movw $enoboot, %si
|
||||
|
||||
err_stop:
|
||||
call Lmessage
|
||||
|
||||
stay_stopped:
|
||||
sti
|
||||
hlt
|
||||
jmp stay_stopped
|
||||
|
||||
found:
|
||||
DBGMSG(CHAR_B)
|
||||
movb %dl, %al
|
||||
andb $0x0f, %al
|
||||
addb $'0', %al
|
||||
movb %al, drive_num
|
||||
|
||||
movb $'0'+4, %al
|
||||
subb %cl, %al
|
||||
movb %al, part_num
|
||||
pushw %si
|
||||
movw $info, %si
|
||||
call Lmessage
|
||||
popw %si
|
||||
movw $0, %es:signature(,1)
|
||||
movb %dl, (%si)
|
||||
movw $0x55AA, %bx
|
||||
movb $0x41, %ah
|
||||
int $0x13
|
||||
|
||||
movb (%si), %dl
|
||||
jc read_error
|
||||
cmpw $0xAA55, %bx
|
||||
jne read_error
|
||||
testb $0x01, %cl
|
||||
jz read_error
|
||||
|
||||
do_lba:
|
||||
movb $CHAR_LBA_READ, %al
|
||||
call Lchr
|
||||
movl 8(%si), %ecx
|
||||
movl %ecx, lba_sector
|
||||
|
||||
pushw %si
|
||||
movb $0x42, %ah
|
||||
movw $lba_command, %si
|
||||
int $0x13
|
||||
popw %si
|
||||
jnc booting_os
|
||||
|
||||
read_error:
|
||||
movw $eread, %si
|
||||
jmp err_stop
|
||||
|
||||
booting_os:
|
||||
puts(crlf)
|
||||
|
||||
cmpw $DOSMBR_SIGNATURE, %es:signature(,1)
|
||||
jne missing_os
|
||||
ljmp $0, $BOOTSEG << 4
|
||||
|
||||
missing_os:
|
||||
movw $enoos, %si
|
||||
jmp err_stop
|
||||
|
||||
Lmessage:
|
||||
pushw %ax
|
||||
cld
|
||||
1:
|
||||
lodsb
|
||||
testb %al, %al
|
||||
jz 1f
|
||||
call Lchr
|
||||
jmp 1b
|
||||
|
||||
Lchr:
|
||||
pushw %ax
|
||||
pushw %bx
|
||||
movb $0x0e, %ah
|
||||
movw $1, %bx
|
||||
int $0x10
|
||||
popw %bx
|
||||
1: popw %ax
|
||||
ret
|
||||
|
||||
lba_command:
|
||||
.byte 0x10
|
||||
.byte 0x00
|
||||
.word 0x0001
|
||||
.word 0
|
||||
.word BOOTSEG
|
||||
lba_sector:
|
||||
.long 0, 0
|
||||
|
||||
info: .ascii "Using drive "
|
||||
drive_num:
|
||||
.byte 'X'
|
||||
.ascii ", partition "
|
||||
part_num:
|
||||
.asciz "Y"
|
||||
|
||||
efdmbr: .asciz "MBR on floppy of old BIOS\r\n"
|
||||
eread: .asciz "\r\nRead error\r\n"
|
||||
enoos: .asciz "No O/S\r\n"
|
||||
enoboot: .ascii "No active partion"
|
||||
crlf: .asciz "\r\n"
|
||||
|
||||
endofcode:
|
||||
nop
|
||||
|
||||
// partion table
|
||||
. = DOSPARTOFF // partion table start address
|
||||
pt: .fill 0x40,1,0
|
||||
|
||||
. = 0x1fe
|
||||
signature:
|
||||
.short DOSMBR_SIGNATURE
|
||||
. = 0x200
|
||||
|
||||
Loading…
Reference in New Issue
Block a user