boot: MBR / disk boot stub

This commit is contained in:
K Lange 2021-10-20 23:00:04 +09:00
parent 55835ab494
commit 707b7f7ed2
6 changed files with 347 additions and 16 deletions

1
.gitignore vendored
View File

@ -30,3 +30,4 @@
/cdrom
/fatbase
/image.iso
/boot/mbr.sys

View File

@ -308,10 +308,15 @@ BUILD_KRK=$(TOOLCHAIN)/local/bin/kuroko
$(TOOLCHAIN)/local/bin/kuroko: kuroko/src/*.c
cc -Ikuroko/src -DNO_RLINE -DSTATIC_ONLY -DKRK_DISABLE_THREADS -o "${TOOLCHAIN}/local/bin/kuroko" kuroko/src/*.c
image.iso: cdrom/fat.img cdrom/boot.sys util/update-extents.krk $(BUILD_KRK)
image.iso: cdrom/fat.img cdrom/boot.sys boot/mbr.S util/update-extents.krk | $(BUILD_KRK)
xorriso -as mkisofs -R -J -c bootcat \
-b boot.sys -no-emul-boot -boot-load-size full \
-eltorito-alt-boot -e fat.img -no-emul-boot -isohybrid-gpt-basdat \
-o image.iso cdrom
${AS} --32 $$(kuroko util/make_mbr.krk) -o boot/mbr.o boot/mbr.S
${LD} -melf_i386 -T boot/link.ld -o boot/mbr.sys boot/mbr.o
tail -c +513 image.iso > image.dat
cat boot/mbr.sys image.dat > image.iso
rm image.dat
kuroko util/update-extents.krk

View File

@ -70,6 +70,8 @@ can_long:
movl $str_More_mem, %esi
call print_string
_oh_no:
jmp _oh_no
good_memory:
@ -79,17 +81,6 @@ good_memory:
mov $drive_params, %si
int $0x13
/* Are we a CD? Do we need to load more of ourselves? */
mov drive_params_bps, %ax
cmp $0x800, %ax
je boot_from_cd
movl $str_Bad, %esi
call print_string
_oh_no:
jmp _oh_no
.extern _bss_start
boot_from_cd:
@ -359,8 +350,6 @@ drive_params:
drive_params_bps:
.word 0 /* bytes per sector */
str_Bad:
.asciz "The boot disk does not seem to be a CD."
str_Need_long:
.asciz "ToaruOS 2.0 requires a 64-bit processor."
str_More_mem:

91
boot/mbr.S Normal file
View File

@ -0,0 +1,91 @@
.code16
main:
/* fix up code seg */
ljmp $0x0,$entry
entry:
/* init data segments */
xor %ax, %ax
mov %ax, %ds
mov %ax, %ss
/* save boot disk */
mov %dl, boot_disk
/* set up stack */
mov $0x7b00, %ax
mov %ax, %sp
/* figure out sector size */
mov $0x48, %ah
mov boot_disk, %dl
mov $drive_params, %si
int $0x13
/* figure out first sector of stage 2 */
mov $0, %edx
mov $BOOT_FILE_OFFSET, %eax
mov (drive_params_bps), %ecx
div %ecx
mov %eax, dap_lba_low
mov $BOOT_FILE_SIZE, %eax
div %ecx
inc %eax
mov %ax, dap_sectors
movl $0x7e00, dap_buffer
mov $0x42, %ah /* Extended read */
mov boot_disk, %dl /* Using our boot disk */
mov $dap, %si /* From the DAP below */
int $0x13
mov $0, %ax
mov %ax, %es
mov %ax, %ds
/* Now move the rest of our code somewhere low */
mov $mover, %esi
mov $0x7b00, %edi
mov $(mover_end-mover), %ecx
rep movsb
mov $0x7b00, %eax
jmp *%eax
mover:
mov $0x7e00, %esi
mov $0x7c00, %edi
mov $BOOT_FILE_SIZE, %ecx
rep movsb
mov $0x7c00, %eax
jmp *%eax
mover_end:
boot_disk:
.byte 0
.align 4
.global dap
dap:
.byte 16
.byte 0 /* always 0 */
.global dap_sectors
dap_sectors:
.word 1
.global dap_buffer
dap_buffer:
.long 0x0
.global dap_lba_low
dap_lba_low:
.long 0
.global dap_lba_high
dap_lba_high:
.long 0
.align 4
drive_params:
.word 0x1A
.word 0 /* flags */
.long 0 /* cylinders */
.long 0 /* heads */
.long 0 /* sectors */
.quad 0 /* total sectors */
drive_params_bps:
.word 0 /* bytes per sector */
.org 510
.byte 0x55
.byte 0xaa

View File

@ -69,13 +69,14 @@ extern volatile uint16_t dap_sectors;
extern volatile uint32_t dap_buffer;
extern volatile uint32_t dap_lba_low;
extern volatile uint32_t dap_lba_high;
extern volatile uint16_t drive_params_bps;
extern uint8_t disk_space[];
int bios_call(char * into, uint32_t sector) {
dap_sectors = 2048 / drive_params_bps;
dap_buffer = (uint32_t)disk_space;
dap_lba_low = sector;
dap_lba_low = sector * dap_sectors;
dap_lba_high = 0;
dap_sectors = 1;
do_bios_call();
memcpy(into, disk_space, 2048);
}

244
util/make_mbr.krk Normal file
View File

@ -0,0 +1,244 @@
#!/usr/bin/env kuroko
import fileio
def to_int(little: bool, data: bytes):
let out = 0
if little: data = reversed(data)
for x in data:
out *= 0x100
out += x
return out
def to_bytes(little: bool, val: int, length: int):
let out = [0] * length
let i = 0
while val and i < length:
out[i] = val & 0xFF
val >>= 8
i++
if not little:
out = reversed(out)
return bytes(out)
def read_struct(fmt: str, data: bytes, offset: int):
if not fmt or not isinstance(fmt,str):
raise ValueError
# First, read the endianness
let littleEndian = True
if fmt[0] in '@<>#!':
if fmt[0] == '>': littleEndian = False
else if fmt[0] == '!': littleEndian = False
fmt = fmt[1:]
# Then read length
let length = None
if fmt[0] in '0123456789':
length = int(fmt[0])
fmt = fmt[1:]
while fmt[0] in '012345679':
length *= 10
length += int(fmt[0])
fmt = fmt[1:]
# Then read type
if fmt[0] == 'B':
return int(data[offset]), offset + 1
else if fmt[0] == 'b':
let out = int(data[offset])
if out > 0x7F: out = -out
return out, offset + 1
else if fmt[0] == 's':
return bytes([data[x] for x in range(offset,offset+length)]), offset + length
else if fmt[0] == 'I':
return to_int(littleEndian, bytes([data[x] for x in range(offset,offset+4)])), offset + 4
else if fmt[0] == 'H':
return to_int(littleEndian, bytes([data[x] for x in range(offset,offset+2)])), offset + 2
raise ValueError("Huh")
def pack_into(fmt: str, data: bytes, offset: int, val: any):
if not fmt or not isinstance(fmt,str):
raise ValueError
# First, read the endianness
let littleEndian = True
if fmt[0] in '@<>#!':
if fmt[0] == '>': littleEndian = False
else if fmt[0] == '!': littleEndian = False
fmt = fmt[1:]
# Then read length
let length = None
if fmt[0] in '0123456789':
length = int(fmt[0])
fmt = fmt[1:]
while fmt[0] in '012345679':
length *= 10
length += int(fmt[0])
fmt = fmt[1:]
# Then read type
if fmt[0] == 'B':
data[offset] = val
return offset + 1
else if fmt[0] == 'b':
data[offset] = val
return offset + 1
else if fmt[0] == 's':
for x in range(length):
data[offset+x] = val[x]
return offset + length
else if fmt[0] == 'I':
for x in to_bytes(littleEndian, val, 4):
data[offset] = x
offset++
return offset
else if fmt[0] == 'H':
for x in to_bytes(littleEndian, val, 2):
data[offset] = x
offset++
return offset
raise ValueError("Huh")
class ISO(object):
def __init__(self, path):
let data
with fileio.open(path, 'rb') as f:
self.data = bytearray(f.read())
self.sector_size = 2048
let o = 0x10 * self.sector_size
let _unused
self.type, o = read_struct('B',self.data,o)
self.id, o = read_struct('5s',self.data,o)
self.version, o = read_struct('B',self.data,o)
_unused, o = read_struct('B',self.data,o)
self.system_id, o = read_struct('32s',self.data,o)
self.volume_id, o = read_struct('32s',self.data,o)
_unused, o = read_struct('8s',self.data,o)
self.volume_space_lsb, o = read_struct('<I',self.data,o)
self.volume_space_msb, o = read_struct('>I',self.data,o)
_unused, o = read_struct('32s',self.data,o)
self.volume_set_lsb, o = read_struct('<H',self.data,o)
self.volume_set_msb, o = read_struct('>H',self.data,o)
self.volume_seq_lsb, o = read_struct('<H',self.data,o)
self.volume_seq_msb, o = read_struct('>H',self.data,o)
self.logical_block_size_lsb, o = read_struct('<H',self.data,o)
self.logical_block_size_msb, o = read_struct('>H',self.data,o)
self.path_table_size_lsb, o = read_struct('<I',self.data,o)
self.path_table_size_msb, o = read_struct('>I',self.data,o)
self.path_table_lsb, o = read_struct('<I',self.data,o)
self.optional_path_table_lsb, o = read_struct('<I',self.data,o)
self.path_table_msb, o = read_struct('>I',self.data,o)
self.optional_path_table_msb, o = read_struct('>I',self.data,o)
let _offset = o
self.root_dir_entry, o = read_struct('34s',self.data,o)
self.root = ISOFile(self,_offset)
self._cache = {}
def get_file(self, path):
if path == '/':
return self.root
else:
if path in self._cache:
return self._cache[path]
let units = path.split('/')
units = units[1:] # remove root
let me = self.root
for i in units:
let next_file = me.find(i)
if not next_file:
me = None
break
else:
me = next_file
self._cache[path] = me
return me
class ISOFile(object):
def __init__(self, iso, offset):
self.iso = iso
self.offset = offset
let o = offset
self.length, o = read_struct('B', self.iso.data, o)
if not self.length:
return
self.ext_length, o = read_struct('B', self.iso.data, o)
self.extent_start_lsb, o = read_struct('<I',self.iso.data, o)
self.extent_start_msb, o = read_struct('>I',self.iso.data, o)
self.extent_length_lsb, o = read_struct('<I',self.iso.data, o)
self.extent_length_msb, o = read_struct('>I',self.iso.data, o)
self.date_data, o = read_struct('7s', self.iso.data, o)
self.flags, o = read_struct('b', self.iso.data, o)
self.interleave_units, o = read_struct('b', self.iso.data, o)
self.interleave_gap, o = read_struct('b', self.iso.data, o)
self.volume_seq_lsb, o = read_struct('<H',self.iso.data, o)
self.volume_seq_msb, o = read_struct('>H',self.iso.data, o)
self.name_len, o = read_struct('b', self.iso.data, o)
self.name, o = read_struct('{}s'.format(self.name_len), self.iso.data, o)
self.name = self.name.decode()
def __str__(self):
return f'<ISOFile name={self.name} start={self.extent_start_lsb * self.iso.sector_size} length={self.extent_length_lsb}>'
def write_extents(self):
pack_into('<I', self.iso.data, self.offset + 2, self.extent_start_lsb)
pack_into('>I', self.iso.data, self.offset + 6, self.extent_start_lsb)
pack_into('<I', self.iso.data, self.offset + 10, self.extent_length_lsb)
pack_into('>I', self.iso.data, self.offset + 14, self.extent_length_lsb)
def readable_name(self):
if not ';' in self.name:
return self.name.lower()
else:
let tmp, _
tmp, _ = self.name.split(';')
return tmp.lower()
def list(self):
let sectors = self.iso.data[self.extent_start_lsb * self.iso.sector_size: self.extent_start_lsb * self.iso.sector_size+ 3 * self.iso.sector_size]
let offset = 0
while 1:
let f = ISOFile(self.iso, self.extent_start_lsb * self.iso.sector_size + offset)
yield f
offset += f.length
if not f.length:
break
def find(self, name):
let sectors = self.iso.data[self.extent_start_lsb * self.iso.sector_size: self.extent_start_lsb * self.iso.sector_size+ 3 * self.iso.sector_size]
let offset = 0
if '.' in name and len(name.split('.')[0]) > 8:
let a, b
a, b = name.split('.')
name = a[:8] + '.' + b
if '-' in name:
name = name.replace('-','_')
while 1:
let f = ISOFile(self.iso, self.extent_start_lsb * self.iso.sector_size + offset)
if not f.length:
if offset < self.extent_length_lsb:
offset += 1
continue
else:
break
if ';' in f.name:
let tmp, _
tmp, _ = f.name.split(';')
if tmp.endswith('.'):
tmp = tmp[:-1]
if tmp.lower() == name.lower():
return f
elif f.name.lower() == name.lower():
return f
offset += f.length
return None
let image = ISO('image.iso')
let cdfile = image.get_file('/boot.sys')
print(f'--defsym BOOT_FILE_SIZE={cdfile.extent_length_lsb} --defsym BOOT_FILE_OFFSET={cdfile.extent_start_lsb * 2048}')