Browse Source

boot: MBR / disk boot stub

K Lange 11 months ago
parent
commit
707b7f7ed2
6 changed files with 347 additions and 16 deletions
  1. 1 0
      .gitignore
  2. 6 1
      Makefile
  3. 2 13
      boot/boot.S
  4. 91 0
      boot/mbr.S
  5. 3 2
      boot/platform.c
  6. 244 0
      util/make_mbr.krk

+ 1 - 0
.gitignore

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

+ 6 - 1
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
 

+ 2 - 13
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:

+ 91 - 0
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

+ 3 - 2
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);
 }

+ 244 - 0
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)
+        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}')
+