From 707b7f7ed23297f6182121425ee53eb814975331 Mon Sep 17 00:00:00 2001 From: K Lange Date: Wed, 20 Oct 2021 23:00:04 +0900 Subject: [PATCH] boot: MBR / disk boot stub --- .gitignore | 1 + Makefile | 7 +- boot/boot.S | 15 +-- boot/mbr.S | 91 +++++++++++++++++ boot/platform.c | 5 +- util/make_mbr.krk | 244 ++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 347 insertions(+), 16 deletions(-) create mode 100644 boot/mbr.S create mode 100644 util/make_mbr.krk diff --git a/.gitignore b/.gitignore index a7d1041f..cd495325 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,4 @@ /cdrom /fatbase /image.iso +/boot/mbr.sys diff --git a/Makefile b/Makefile index 3533352a..4efe8db7 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/boot/boot.S b/boot/boot.S index cf12e7b0..e873c506 100644 --- a/boot/boot.S +++ b/boot/boot.S @@ -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: diff --git a/boot/mbr.S b/boot/mbr.S new file mode 100644 index 00000000..1acdd244 --- /dev/null +++ b/boot/mbr.S @@ -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 diff --git a/boot/platform.c b/boot/platform.c index 261c3a10..ee3df048 100644 --- a/boot/platform.c +++ b/boot/platform.c @@ -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); } diff --git a/util/make_mbr.krk b/util/make_mbr.krk new file mode 100644 index 00000000..eb02a6ee --- /dev/null +++ b/util/make_mbr.krk @@ -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) + _unused, o = read_struct('32s',self.data,o) + self.volume_set_lsb, o = read_struct('H',self.data,o) + self.volume_seq_lsb, o = read_struct('H',self.data,o) + self.logical_block_size_lsb, o = read_struct('H',self.data,o) + self.path_table_size_lsb, o = read_struct('I',self.data,o) + self.path_table_lsb, 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_length_lsb, 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.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'' + + def write_extents(self): + pack_into('I', self.iso.data, self.offset + 6, self.extent_start_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}') +