2日目
時間があいてしまいましたが、ようやく2日目に着手しました。ソース。
今回からフロッピーディスクのイメージをRubyスクリプトで生成しています。IPLの部分は、これまで機械語データ埋め込みでしたがアセンブラで書きました。
02/Makefile
TARGET=henaos ${TARGET}.img: ${TARGET}.S gcc -c -o ${TARGET}.o ${TARGET}.S ld -o ${TARGET}.tmp1 -Ttext 0x7c50 ${TARGET}.o objcopy -O binary ${TARGET}.tmp1 ${TARGET}.tmp2 ./fdutl.rb -o ${TARGET}.img ${TARGET}.tmp2 .PHONY: clean clean: rm -f *.o *.tmp? *.img .PHONY: run run: ${TARGET}.img qemu -net none -m 8 -boot a -fda ${TARGET}.img
02/fdutl.rb
#!/usr/bin/env ruby # -*- ruby -*- # $Id:$ require 'ostruct' $opts = OpenStruct.new(:debug => 0, :output => $stdout) class String def overwrite!(str, off = 0) str.size.times do |i| self[off + i] = str[i] end end end def creatre_fat12_bootsector [ ['C3', [0xeb, 0x4e, 0x90]], ['a8', ['HENA-IPL']], # ブートセクタの名前を自由に書いてよい(8バイト) ['S', [512]], # 1セクタの大きさ(512にしなければいけない) ['C', [1]], # クラスタの大きさ(1セクタにしなければいけない) ['S', [1]], # FATがどこから始まるか(普通は1セクタ目からにする) ['C', [2]], # FATの個数(2にしなければいけない) ['S', [224]], # ルートディレクトリ領域の大きさ(普通は224エントリにする) ['S', [2880]], # このドライブの大きさ(2880セクタにしなければいけない) ['C', [0xf0]], # メディアのタイプ(0xf0にしなければいけない) ['S', [9]], # FAT領域の長さ(9セクタにしなければいけない) ['S', [18]], # 1トラックにいくつのセクタがあるか(18にしなければいけない) ['S', [2]], # ヘッドの数(2にしなければいけない) ['L', [0]], # パーティションを使ってないのでここは必ず0 ['L', [2880]], # このドライブ大きさをもう一度書く ['C3', [0, 0, 0x29]], ['L', [0xffffffff]], ['a11', ['HENA-OS ']], # ディスクの名前(11バイト) ['a8', ['FAT12 ']], # フォーマットの名前(8バイト) ].inject('') do |header, filed| header + filed[1].pack(filed[0]) end end def create_fdimage fdimage = "\0" * 512 * 2880 fdimage.overwrite!(creatre_fat12_bootsector) fdimage.overwrite!([0x55, 0xaa, 0xf0, 0xff, 0xff].pack('C*'), 0x1fe) fdimage.overwrite!([0xf0, 0xff, 0xff].pack('C*'), 0x1400) fdimage end def main(iplfilename) fdimage = create_fdimage open(iplfilename, 'r') do |iplfile| fdimage.overwrite!(iplfile.read, 0x50) end $opts.output.print fdimage end if __FILE__ == $0 require 'optparse' Version = '0.1a' parser = OptionParser.new do |opt| opt.on('-d', '--debug', 'enable debug mode.') do $opts.debug += 1 end opt.on('-o', '--output [filename]', 'output filename.') do |filename| $opts.output = open(filename, 'w') end opt.parse!(ARGV) end if ARGV.size < 1 print parser.help exit 2 end main(ARGV[0]) end
02/henaos.S
#define ENTRY(x) .globl x; .type x,@function; x: .text .code16 ENTRY(_start) /* initialize register */ movw $0, %ax movw %ax, %ss movw $0x7c00, %sp movw %ax, %ds movw %ax, %es movw $mesg, %si put: movb (%si), %al addw $1, %si cmpb $0, %al je fin movb $0x0e, %ah movw $15, %bx int $0x10 jmp put fin: hlt jmp fin mesg: .asciz "\n\nHello, Hena-OS world!!\n"
今回のポイントは、ldコマンドの-Ttext 0x7c50かな。フロッピーディスクの先頭セクタはBIOSが0x7c00に読み込んでくれます。IPLは先頭セクタのオフセット0x50から始まるので、0x7c50のアドレスにリンクしてます。
そうそう、Rubyスクリプト中で文字列の一部(部分文字列)を上書きをするメソッドを自分で定義しています。標準あってもよさそうなものですが…