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スクリプト中で文字列の一部(部分文字列)を上書きをするメソッドを自分で定義しています。標準あってもよさそうなものですが…