Browse Source

Implement diskfs.

Giovanni Mascellani 5 years ago
parent
commit
976b604c0a
8 changed files with 501 additions and 18 deletions
  1. 9 2
      Makefile
  2. 12 4
      asmg/atapio.g
  3. 246 0
      asmg/diskfs.g
  4. 16 8
      asmg/main.g
  5. 149 0
      asmg/mbr.g
  6. 6 0
      asmg/vfs.g
  7. 63 0
      create_diskfs.py
  8. 0 4
      create_partition.py

+ 9 - 2
Makefile

@@ -50,6 +50,13 @@ build/bootloader.x86.mbr: build/bootloader.x86.exe
 build/bootloader.x86.stage2: build/bootloader.x86.exe
 	tail -c +513 $< > $@
 
+# Diskfs image
+build/diskfs.list: script-data/*
+	(cd script-data/ ; find -type f) | cut -c3- | sed -e 's|\(.*\)|\1 script-data/\1|' > $@
+
+build/diskfs.img: build/diskfs.list
+	xargs ./create_diskfs.py < $< > $@
+
 # Asmasm executable
 build/asmasm_linux.asm: asmasm/asmasm_linux.asm lib/library.asm asmasm/asmasm.asm
 	cat $^ > $@
@@ -115,7 +122,7 @@ build/script.g:
 build/full-asmg.asm: lib/multiboot.asm lib/kernel.asm lib/shutdown.asm lib/ar.asm lib/library.asm asmg/asmg.asm asmg/kernel-asmg.asm lib/top.asm
 	cat $^ | grep -v "^ *section " > $@
 
-build/initrd-asmg.ar: asmg/*.g build/script.g test/test.hex2 test/test.m1 test/test.c test/first.h test/other.h test/test_mes.c test/test.asm script-data/* build/END
+build/initrd-asmg.ar: asmg/*.g build/script.g test/test.hex2 test/test.m1 test/test.c test/first.h test/other.h test/test_mes.c test/test.asm build/END
 	-rm $@
 	$(AR) rcs $@ $^
 
@@ -130,7 +137,7 @@ endif
 build/asmg.x86: build/asmg.x86.exe build/initrd-asmg.ar
 	cat $^ > $@
 
-build/boot_asmg.x86: build/bootloader.x86.mbr build/bootloader.x86.stage2 build/asmg.x86
+build/boot_asmg.x86: build/bootloader.x86.mbr build/bootloader.x86.stage2 build/asmg.x86 build/diskfs.img
 	./create_partition.py $^ > $@
 
 # Asmg0 kernel

+ 12 - 4
asmg/atapio.g

@@ -41,6 +41,13 @@ fun atapio_init 2 {
   a ret ;
 }
 
+fun atapio_duplicate 1 {
+  $a
+  @a 0 param = ;
+
+  a ATAPIO_BASE take a ATAPIO_MASTER take atapio_init ret ;
+}
+
 fun atapio_destroy 1 {
   $a
   @a 0 param = ;
@@ -212,7 +219,8 @@ fun atapio_print_identify 1 {
   # data 512 dump_mem ;
   # "\n" 1 platform_log ;
 
-  "Model number: " 1 platform_log ;
+  "Found disk!\n" 1 platform_log ;
+  "  Model number: " 1 platform_log ;
   $i
   @i 27 = ;
   while i 47 < {
@@ -222,7 +230,7 @@ fun atapio_print_identify 1 {
   }
   "\n" 1 platform_log ;
 
-  "Serial number: " 1 platform_log ;
+  "  Serial number: " 1 platform_log ;
   $i
   @i 10 = ;
   while i 20 < {
@@ -232,7 +240,7 @@ fun atapio_print_identify 1 {
   }
   "\n" 1 platform_log ;
 
-  "Firmware revision: " 1 platform_log ;
+  "  Firmware revision: " 1 platform_log ;
   $i
   @i 23 = ;
   while i 27 < {
@@ -244,7 +252,7 @@ fun atapio_print_identify 1 {
 
   $size
   @size data 2 60 * + ** = ;
-  "Drive has " 1 platform_log ;
+  "  Size: " 1 platform_log ;
   size itoa 1 platform_log ;
   " sectors\n" 1 platform_log ;
 

+ 246 - 0
asmg/diskfs.g

@@ -0,0 +1,246 @@
+# This file is part of asmc, a bootstrapping OS with minimal seed
+# Copyright (C) 2018 Giovanni Mascellani <gio@debian.org>
+# https://gitlab.com/giomasce/asmc
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+const DISKFD_DESTROY 0
+const DISKFD_READ 4
+const DISKFD_WRITE 8
+const DISKFD_TRUNCATE 12
+const DISKFD_RESET 16
+const DISKFD_POS 20
+const DISKFD_ATAPIO 24
+const DISKFD_SIZE 28
+const DISKFD_START 32
+const DISKFD_CACHE 36
+const SIZEOF_DISKFD 40
+
+fun diskfd_destroy 1 {
+  $fd
+  @fd 0 param = ;
+
+  fd DISKFD_CACHE take free ;
+  fd free ;
+}
+
+fun diskfd_read 1 {
+  $fd
+  @fd 0 param = ;
+
+  fd DISKFD_POS take fd DISKFD_SIZE take <= "diskfd_read: invalid read position" assert_msg ;
+  if fd DISKFD_POS take fd DISKFD_SIZE take == {
+    0xffffffff ret ;
+  }
+  $pos
+  @pos fd DISKFD_POS take fd DISKFD_START take + = ;
+  $sect_pos
+  @sect_pos pos 512 % = ;
+  $cache
+  @cache fd DISKFD_CACHE take = ;
+  if cache 0 == {
+    $sect_num
+    @sect_num pos 512 / = ;
+    $atapio
+    @atapio fd DISKFD_ATAPIO take = ;
+    @cache atapio sect_num atapio_read_sect = ;
+    fd DISKFD_CACHE take_addr cache = ;
+  }
+  $c
+  @c cache sect_pos + **c = ;
+  if sect_pos 511 == {
+    cache free ;
+    fd DISKFD_CACHE take_addr 0 = ;
+  }
+  fd DISKFD_POS take_addr fd DISKFD_POS take 1 + = ;
+  # "Read char " 1 platform_log ;
+  # c itoa 1 platform_log ;
+  # "\n" 1 platform_log ;
+  c ret ;
+}
+
+fun diskfd_write 2 {
+  $fd
+  $c
+  @fd 1 param = ;
+  @c 0 param = ;
+
+  0 "diskfd_write: not supported" assert_msg ;
+}
+
+fun diskfd_truncate 1 {
+  $fd
+  @fd 0 param = ;
+
+  0 "diskfd_truncate: not supported" assert_msg ;
+}
+
+fun diskfd_reset 1 {
+  $fd
+  @fd 0 param = ;
+
+  fd DISKFD_POS take_addr 0 = ;
+  fd DISKFD_CACHE take free ;
+  fd DISKFD_CACHE take_addr 0 = ;
+}
+
+fun diskfd_init 3 {
+  $atapio
+  $start
+  $size
+  @atapio 2 param = ;
+  @start 1 param = ;
+  @size 0 param = ;
+
+  $fd
+  @fd SIZEOF_DISKFD malloc = ;
+  fd DISKFD_DESTROY take_addr @diskfd_destroy = ;
+  fd DISKFD_READ take_addr @diskfd_read = ;
+  fd DISKFD_WRITE take_addr @diskfd_write = ;
+  fd DISKFD_TRUNCATE take_addr @diskfd_truncate = ;
+  fd DISKFD_RESET take_addr @diskfd_reset = ;
+  fd DISKFD_POS take_addr 0 = ;
+  fd DISKFD_ATAPIO take_addr atapio = ;
+  fd DISKFD_START take_addr start = ;
+  fd DISKFD_SIZE take_addr size = ;
+  fd DISKFD_CACHE take_addr 0 = ;
+
+  fd ret ;
+}
+
+const DISKMOUNT_DESTROY 0
+const DISKMOUNT_OPEN 4
+const DISKMOUNT_ATAPIO 8
+const DISKMOUNT_STARTS 12
+const DISKMOUNT_SIZES 16
+const SIZEOF_DISKMOUNT 20
+
+fun diskmount_destroy 1 {
+  $disk
+  @disk 0 param = ;
+
+  disk DISKMOUNT_STARTS take map_destroy ;
+  disk DISKMOUNT_SIZES take map_destroy ;
+  disk DISKMOUNT_ATAPIO take atapio_destroy ;
+  disk free ;
+}
+
+fun diskmount_open 2 {
+  $disk
+  $name
+  @disk 1 param = ;
+  @name 0 param = ;
+
+  disk DISKMOUNT_STARTS take name map_has "diskmount_open: file does not exist" assert_msg ;
+  disk DISKMOUNT_SIZES take name map_has "diskmount_open: error 1" assert_msg ;
+  disk DISKMOUNT_ATAPIO take disk DISKMOUNT_STARTS take name map_at disk DISKMOUNT_SIZES take name map_at diskfd_init ret ;
+}
+
+fun diskmount_init 2 {
+  $atapio
+  $start
+  @atapio 1 param = ;
+  @start 0 param = ;
+
+  $disk
+  @disk SIZEOF_DISKMOUNT malloc = ;
+  disk DISKMOUNT_DESTROY take_addr @diskmount_destroy = ;
+  disk DISKMOUNT_OPEN take_addr @diskmount_open = ;
+  disk DISKMOUNT_ATAPIO take_addr atapio = ;
+  disk DISKMOUNT_STARTS take_addr map_init = ;
+  disk DISKMOUNT_SIZES take_addr map_init = ;
+
+  # Parse the file table
+  $fd
+  @fd atapio start 0x7fffffff diskfd_init = ;
+
+  # Discard the first eight byte (magic number)
+  $i
+  @i 0 = ;
+  while i 8 < {
+    fd diskfd_read ;
+    @i i 1 + = ;
+  }
+
+  $cont
+  @cont 1 = ;
+  while cont {
+    # Scan the filename
+    $filename
+    $cap
+    $len
+    @cap 10 = ;
+    @len 0 = ;
+    @filename cap malloc = ;
+    $cont2
+    @cont2 1 = ;
+    while cont2 {
+      if len cap == {
+        @cap cap 2 * = ;
+        @filename cap filename realloc = ;
+      }
+      len cap < "diskmount_init: error 1" assert_msg ;
+      $c
+      @c fd diskfd_read =c ;
+      filename len + c =c ;
+      if c 0 == {
+        @cont2 0 = ;
+      } else {
+        @len len 1 + = ;
+      }
+    }
+
+    if len 0 == {
+      filename free ;
+      @cont 0 = ;
+    } else {
+      # Read the position
+      $pos
+      @pos fd diskfd_read = ;
+      @pos pos 8 << fd diskfd_read + = ;
+      @pos pos 8 << fd diskfd_read + = ;
+      @pos pos 8 << fd diskfd_read + = ;
+
+      # Read the size
+      $size
+      @size fd diskfd_read = ;
+      @size size 8 << fd diskfd_read + = ;
+      @size size 8 << fd diskfd_read + = ;
+      @size size 8 << fd diskfd_read + = ;
+
+      # Store data in tables
+      disk DISKMOUNT_STARTS take filename map_has ! "diskmount_init: duplicated file name" assert_msg ;
+      disk DISKMOUNT_SIZES take filename map_has ! "diskmount_init: error 2" assert_msg ;
+      disk DISKMOUNT_STARTS take filename start pos + map_set ;
+      disk DISKMOUNT_SIZES take filename size map_set ;
+      disk DISKMOUNT_STARTS take filename map_has "diskmount_init: error 3" assert_msg ;
+      disk DISKMOUNT_SIZES take filename map_has "diskmount_init: error 4" assert_msg ;
+
+      # Debug log
+      # "File " 1 platform_log ;
+      # filename 1 platform_log ;
+      # " at position " 1 platform_log ;
+      # pos itoa 1 platform_log ;
+      # " of size " 1 platform_log ;
+      # size itoa 1 platform_log ;
+      # "\n" 1 platform_log ;
+
+      filename free ;
+    }
+  }
+
+  fd diskfd_destroy ;
+
+  disk ret ;
+}

+ 16 - 8
asmg/main.g

@@ -15,12 +15,12 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-const COMPILE_ASM 1
+const COMPILE_ASM 0
 const COMPILE_C 1
-const COMPILE_MESCC 1
-const RUN_ASM 1
+const COMPILE_MESCC 0
+const RUN_ASM 0
 const RUN_C 1
-const RUN_MESCC 1
+const RUN_MESCC 0
 
 const USE_TRIVIAL_MALLOC 0
 const USE_SIMPLE_MALLOC 0
@@ -71,12 +71,20 @@ fun main 0 {
   "utils2.g" platform_g_compile ;
   "done!\n" 1 platform_log ;
 
+  "Compiling atapio.g... " 1 platform_log ;
+  "atapio.g" platform_g_compile ;
+  "done!\n" 1 platform_log ;
+
+  "Compiling diskfs.g... " 1 platform_log ;
+  "diskfs.g" platform_g_compile ;
+  "done!\n" 1 platform_log ;
+
   "Compiling ramfs.g... " 1 platform_log ;
   "ramfs.g" platform_g_compile ;
   "done!\n" 1 platform_log ;
 
-  "Compiling atapio.g... " 1 platform_log ;
-  "atapio.g" platform_g_compile ;
+  "Compiling mbr.g... " 1 platform_log ;
+  "mbr.g" platform_g_compile ;
   "done!\n" 1 platform_log ;
 
   "Compiling vfs.g... " 1 platform_log ;
@@ -145,9 +153,9 @@ fun main 0 {
   0 platform_allocate itoa 1 platform_log ;
   "\n" 1 platform_log ;
 
-  "Initializing Virtual File System... " 1 platform_log ;
+  "Initializing Virtual File System...\n" 1 platform_log ;
   0 "vfs_init" platform_get_symbol \0 ;
-  "done!\n" 1 platform_log ;
+  "Virtual File System initialized!\n" 1 platform_log ;
 
   # Determine if there is an actual script
   $script_file

+ 149 - 0
asmg/mbr.g

@@ -0,0 +1,149 @@
+# This file is part of asmc, a bootstrapping OS with minimal seed
+# Copyright (C) 2018 Giovanni Mascellani <gio@debian.org>
+# https://gitlab.com/giomasce/asmc
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+fun read_mbr 1 {
+  $atapio
+  @atapio 0 param = ;
+
+  # Read MBR
+  $mbr
+  @mbr atapio 0 atapio_read_sect = ;
+
+  # Check if this is an actual MBR
+  $res
+  if mbr 510 + **c 0x55 == mbr 511 + **c 0xaa == && {
+    @res 8 vector_init = ;
+    $i
+    @i 0 = ;
+    while i 4 < {
+      $start
+      $size
+      @start mbr 0x1be + i 16 * + 8 + ** = ;
+      @size mbr 0x1be + i 16 * + 12 + ** = ;
+      if start 0 != {
+        $idx
+        @idx res vector_size = ;
+        res start vector_push_back ;
+        res idx vector_at_addr 4 + size = ;
+      }
+      @i i 1 + = ;
+    }
+  } else {
+    @res 0 = ;
+  }
+
+  mbr free ;
+
+  res ret ;
+}
+
+fun mbr_vfs_scan_drive 3 {
+  $vfs
+  $base
+  $master
+  @vfs 2 param = ;
+  @base 1 param = ;
+  @master 0 param = ;
+
+  $count
+  @count 1 = ;
+
+  $a
+  @a base master atapio_init = ;
+  if a atapio_print_identify {
+    $parts
+    @parts a read_mbr = ;
+    if parts 0 != {
+      "Found MBR!\n" 1 platform_log ;
+      $i
+      @i 0 = ;
+      while i parts vector_size < {
+        "  Partition starting at LBA " 1 platform_log ;
+        parts i vector_at itoa 1 platform_log ;
+        " of size " 1 platform_log ;
+        parts i vector_at_addr 4 + ** itoa 1 platform_log ;
+        "\n" 1 platform_log ;
+
+        # Read the first sector to see if there is a known file system
+        $sect
+        @sect a parts i vector_at atapio_read_sect = ;
+        if sect ** "DISK" ** == sect 4 + ** "FS  " ** == && {
+          "    Found a diskfs file system!\n" 1 platform_log ;
+          $mount
+          @mount a atapio_duplicate 512 parts i vector_at * diskmount_init = ;
+          $point
+          @point "disk" strdup count itoa append_to_str = ;
+          vfs point  mount 0 "vfsinst_mount" platform_get_symbol \3 ;
+          point free ;
+          @count count 1 + = ;
+        }
+        sect free ;
+
+        @i i 1 + = ;
+      }
+      parts vector_destroy ;
+    } else {
+      "No MBR found...\n" 1 platform_log ;
+    }
+  }
+
+  a atapio_destroy ;
+}
+
+fun mbr_vfs_scan 1 {
+  $vfs
+  @vfs 0 param = ;
+
+  vfs 0x1f0 1 mbr_vfs_scan_drive ;
+  vfs 0x1f0 0 mbr_vfs_scan_drive ;
+  vfs 0x170 1 mbr_vfs_scan_drive ;
+  vfs 0x170 0 mbr_vfs_scan_drive ;
+}
+
+fun mbr_read_test_drive 2 {
+  $base
+  $master
+  @base 1 param = ;
+  @master 0 param = ;
+
+  $a
+  @a base master atapio_init = ;
+  if a atapio_print_identify {
+    $parts
+    @parts a read_mbr = ;
+    $i
+    @i 0 = ;
+    while i parts vector_size < {
+      "Partition starting at LBA " 1 platform_log ;
+      parts i vector_at itoa 1 platform_log ;
+      " of size " 1 platform_log ;
+      parts i vector_at_addr 4 + ** itoa 1 platform_log ;
+      "\n" 1 platform_log ;
+      @i i 1 + = ;
+    }
+    parts vector_destroy ;
+  }
+
+  a atapio_destroy ;
+}
+
+fun mbr_read_test 0 {
+  0x1f0 1 mbr_read_test_drive ;
+  0x1f0 0 mbr_read_test_drive ;
+  0x170 1 mbr_read_test_drive ;
+  0x170 0 mbr_read_test_drive ;
+}

+ 6 - 0
asmg/vfs.g

@@ -139,6 +139,10 @@ fun vfsinst_mount 3 {
   @point 1 param = ;
   @mount 0 param = ;
 
+  "Mounting file system /" 1 platform_log ;
+  point 1 platform_log ;
+  "\n" 1 platform_log ;
+
   $mounts
   @mounts vfsinst VFSINST_MOUNTS take = ;
   mounts point mount map_set ;
@@ -177,6 +181,7 @@ fun vfsinst_open 2 {
   @mountpath mountname slash_pos + 1 + = ;
 
   $mount
+  mount vfsinst VFSINST_MOUNTS take mountname map_has "vfsinst_open: mount point does not exist" assert_msg ;
   @mount vfsinst VFSINST_MOUNTS take mountname map_at = ;
   $res
   @res mount mountpath mount MOUNT_OPEN take \2 = ;
@@ -192,6 +197,7 @@ fun vfs_init 0 {
   @vfs vfsinst_init = ;
   vfs "init" initmount_init vfsinst_mount ;
   vfs "ram" rammount_init vfsinst_mount ;
+  vfs mbr_vfs_scan ;
 }
 
 fun vfs_destroy 0 {

+ 63 - 0
create_diskfs.py

@@ -0,0 +1,63 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+# This file is part of asmc, a bootstrapping OS with minimal seed
+# Copyright (C) 2018 Giovanni Mascellani <gio@debian.org>
+# https://gitlab.com/giomasce/asmc
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+import sys
+import os
+import struct
+import shutil
+
+def main():
+    assert len(sys.argv) % 2 == 1
+    file_num = (len(sys.argv) - 1) // 2
+    table_len = 0
+    files_len = 0
+    names = []
+    sizes = []
+    starts = []
+
+    for i in range(file_num):
+        name = sys.argv[2*i+1].encode('ascii')
+        data_filename = sys.argv[2*i+2]
+        data_size = os.stat(data_filename).st_size
+
+        names.append(name)
+        sizes.append(data_size)
+        starts.append(files_len)
+
+        table_len += 9 + len(name)
+        files_len += data_size
+
+    sys.stdout.buffer.write(b'DISKFS  ')
+    # 8 bytes for DISKFS and one another for the final null
+    table_len += 9
+
+    for i in range(file_num):
+        sys.stdout.buffer.write(names[i])
+        sys.stdout.buffer.write(b'\0')
+        sys.stdout.buffer.write(struct.pack('!II', starts[i] + table_len, sizes[i]))
+
+    sys.stdout.buffer.write(b'\0')
+
+    for i in range(file_num):
+        with open(sys.argv[2*i+2], 'rb') as fin:
+            shutil.copyfileobj(fin, sys.stdout.buffer)
+
+if __name__ == '__main__':
+    main()

+ 0 - 4
create_partition.py

@@ -5,10 +5,6 @@
 # Copyright (C) 2018 Giovanni Mascellani <gio@debian.org>
 # https://gitlab.com/giomasce/asmc
 
-# This file was ported from files in M2-Planet,
-# which have the following copyright notices:
-# Copyright (C) 2016 Jeremiah Orians
-
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or