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