minix 1.1

プロジェクトXである。

スーパー望遠鏡「アルマ」の創造者たちって本で、紙上プロジェクトXしてたんだ。電波で宇宙を見る。日本では野辺山にあるデッシュが有名だ。けど、見たい帯域が水蒸気に邪魔されて、上手く観測出来ない。

歯痒い思いに駆られた天文学者達は、地球上で適した場所探し。チリに良い場所を見つける。雨がほとんど降らない乾いた大地、標高5000mの地。余りに星が沢山見えるものだから、★と★を結んで、星座って事が考えられない。逆に★が無い暗黒の空を結んで星座を連想する現地人。 そんな場所だ。

望遠鏡なら光学式だろう。いえ、可視光も電波の一種。周波数によってエネルギーが異なる。 高い周波数程エネルギーが高い。エネルギーは温度換算出来る。絶対0度ぐらいの周波数で観測したい。周波数で言うと、30GHzぐらい。じゃ、1MHzぐらいは、絶対0度を下回ってしまうのでは? よーく考えたら、反比例の関係になるんで、どこまで行っても絶対0度にはなれないって事なんだろうね。

反射鏡に相当するパラボラアンテナの精度が大事。ミクロン級に仕上げないと像がボケる。 軽くする必要が有るので素材はアルミ。切削用の工具を当てるだけで変形してしまうような代物。難題である。町工場の不屈の精神で、画期的な工作法を開発。治具を開発してるようなものだ。

太陽光が当たると温度上昇、逆に日陰は現地の寒い気温。どうする? 風の三菱の面目で、強い風で冷却。それに断熱材で断熱。南米で一番と言う塗装工事屋を探しだす。

望遠鏡を多数配置させて、その電波を合成。ってか、相関を取って雑音の除去。中身はFFTですって。そんな方法が有る事、初めて知った。

昔の天文学者は観測の為の望遠鏡作りでレンズ磨きから始めたそうな。今の天文学者は、電波望遠鏡の設計やら、THz級の30dBアンプに使う石(トランジスタ)まで、自作しちゃう。(どのメーカーも引き受けてくれない為)凄い世界だ箏。

10things to understand ALMA

minix 1.1

QEMU Tips

フリーのエミュレータQEMUを使おう

が膨大な(しかも分かり難い)qemuマニュアルのあんちょこになってて嬉しい。何でこんな事を急に書いてるかと言うと、minix本を見てて、1.1を動かそうと試みたんだ。

Downloads for previous releases

sakae@pen:/tmp/Intel-1.1$ qemu-system-i386 -nographic -fda floppy_disk1
SeaBIOS (version 1.12.0-1)                                               

iPXE (http://ipxe.org) 00:03.0 C980 PCI2.10 PnP PMM+07F90100+07ED0100 C980

Booting from Hard Disk...
Boot failed: could not read the boot disk

Booting from Floppy...
Boot failed: not a bootable disk

Booting from DVD/CD...
Boot failed: Could not read from CDROM (code 0003)
Booting from ROM...
iPXE (PCI 00:03.0) starting execution...ok
iPXE initialising devices...ok

iPXE 1.0.0+git-20190125.36a4c85-1 -- Open Source Network Boot Firmware -- http://ipxe.org
Features: DNS HTTP iSCSI NFS TFTP AoE ELF MBOOT PXE bzImage Menu PXEXT

net0: 52:54:00:12:34:56 using 82540em on 0000:00:03.0 (open)
  :

こんな風にbootを失敗する。

C-a h
C-a h    print this help
C-a x    exit emulator
C-a s    save disk data back to file (if -snapshot)
C-a t    toggle console timestamps
C-a b    send break (magic sysrq)
C-a c    switch between console and monitor
C-a C-a  sends C-a
QEMU 3.1.0 monitor - type 'help' for more information
(qemu) info block
floppy0 (#block151): floppy_disk1 (raw)
    Attached to:      /machine/unattached/device[16]
    Removable device: not locked, tray closed
    Cache mode:       writeback

ide1-cd0: [not inserted]
    Attached to:      /machine/unattached/device[23]
    Removable device: not locked, tray closed

sd0: [not inserted]
    Removable device: not locked, tray closed

ここまで、あんちょこのおかげで、すんなり行った。感謝です。

sakae@pen:/tmp/Intel-1.1$ qemu-system-i386 -fda floppy_disk1 -boot a
WARNING: Image format was not specified for 'floppy_disk1' and probing guessed .
         Automatically detecting the format is dangerous for raw images, write .
         Specify the 'raw' format explicitly to remove the restrictions.

明示的にbootをフロッピーディスクと指定しても、警告が出て来て、グラフィック画面の案内は上記と同様になる。Ctl-Alt-1(or 2)で、グラフィック画面をモニターとかにも切り替えられるけどね。

bootしないって事は、bootableなfloppyとして認めて貰えないって事かな。 マスターブートレコードを見ると、MBRの証拠として、ブートシグネチャ 0xAA55 が必要。そして4つの区画の一つにブートフラグが必要。

hexeditでFloppy_disk1を開いてみると、

000001B0   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  ................
000001C0   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  ................
000001D0   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  ................
000001E0   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  ................
000001F0   00 00 00 00  00 00 00 00  E3 00 27 16  00 00 27 16  ..........'...'.

最後の27 16となってる所を、55 AA に変更して、ブートシグネチャを付加すると

Booting MINIX 1.1

一応、bootした。本の説明では、fsckが起動するはずなんだけど、だんまりである。書き換えてしまった元データに意味が有るんだな。

tools/build.cが、floppy1を作り上げるソフトらしい。

 *      bootblok:       the diskette boot program
 *      kernel:         the operating system kernel
 *      mm:             the memory manager
 *      fs:             the file system
 *      init:           the system initializer
 *      fsck:           the file system checker

こんな風にシステムが配置され

 * begins directly after it.  The kernel, mm, fs, init, and fsck are each
 * padded out to a multiple of 16 bytes, and then concatenated into a
 * single file beginning 512 bytes into the file.  The first byte of sector 1
 * contains executable code for the kernel.  There is no header present.
 *
 * After the boot image has been built, build goes back and makes several
 * patches to the image file or diskette:
 *
 *      1. The last 4 words of the boot block are set as follows:
 *         Word at 504: Number of sectors to load
 *         Word at 506: DS value for running fsck
 *         Word at 508: PC value for starting fsck
 *         Word at 510: CS value for running fsck

こんな風にパッチを当てるそうだ。オイラーが書き換えてしまった部分は、fsckのロードアドレス(0x1627)。これじゃ、暴走するに決まってる。

tools/MINIX/bootblok.s

final   = 504
fsck_ds = 506
fsck_pc = 508
fsck_cs = 510
         :
        mov     ax,fsck_ds      | set segment registers
        mov     ds,ax           | when sep I&D DS != CS
        mov     es,ax           | otherwise they are the same.
        mov     ss,ax           | words 504 - 510 are patched by build

        seg cs
        jmpi    @fsck_pc        | jmp to fsck

binary patch then run

上記のアセンブラーコードに出て来るfsck_csってのが、何処でも参照されていないんだ。不思議な事だ。全体をまとめてパッチを当てるプログラムが、tools/build.cに有るんで、パッチを当ててる部分、patch1()を見ておく。

  read_block(0, ubuf);          /* read in boot block */
  ubuf[(SECTOR_SIZE/2) - 4] = sectrs + 1;
  ubuf[(SECTOR_SIZE/2) - 3] = ds;
  ubuf[(SECTOR_SIZE/2) - 2] = ip;
  ubuf[(SECTOR_SIZE/2) - 1] = cs;
  write_block(0, ubuf);

ipってのはインテル用語。普通語に直すとpcってなる。確かに書き込んでいるね。それしか分からない。

藁をも掴む気持ちで、C86/bootblok.asmの該当部分を見る。C86ってdirはMS-DOSで開発する人用のmakefileとかが入っている。同様にMINIXは頑張ってminixだけで何とかしようという人用。PCIXは、富豪ユーザー用で、PC-UNIXって開発システムを持ってる人用だそうだ。

        mov     ax,fsck_ds      ; set segment registers
        mov     ds,ax           ; when sep I&D ds != cs
        mov     es,ax           ; otherwise they are the same.
        mov     ss,ax           ; This gets patched by 'build'

        jmp     DWORD PTR cs:fsck_pc   ; call the booted program
                                       ; its address is at 508 (dec)

あれれ、jmp命令がcs(コードセグメント)とセットになってるぜ。で、参照元は508番地だ。そうか、508-511番地に存在するcsとpcを使って、ジャンプしろとな。

だったら、508番地(0x1fc)ってのが、生で表れているはず。これを別な番地(0x1f0)に移して、そこに飛び先のセットを置いておけばいいじゃん。そうすれば、シグネチャ用の番地(0xAA55)を確保出来るよ。しばしバイナリアン御用達のhexeditと格闘。

sakae@pen:/tmp$ cmp -l Intel-1.1/floppy_disk1 m-1.1/floppy_disk1
   181 374 360
   499   0  47
   500   0  26
   511  47 125
   512  26 252

Intel-1.1はオリジナル。m-1.1の方はパッチ済のやつ。

このcmpの出力で注意点が3つある。 アドレスが10進表記になってる。アドレスが1オリジンになってる。バイトの表示は古めかしい8進表示になっている。バイナリアンの仕様のdiffじゃ無いって事。

これからもcmpを多用するなら、バイナリアン仕様のcmpxでも作っておくかな。 変更場所は、/usr/src/usr.bin/cmp/regular.c

                          (void)printf("%6lld %3o %3o\n", (long long)byte,
                                              ch1, ch2);
ob$ ./a.out -l Intel-1.1/floppy_disk1 m-1.1/floppy_disk1
    b4  fc  f0
   1f2   0  27
   1f3   0  16
   1fe  27  55
   1ff  16  aa

これで走らせてみる

sakae@pen:/tmp/m-1.1$ qemu-system-i386 -nographic -fda floppy_disk1
Booting MINIX 1.1

Hit key as follows:

    =  start MINIX (root file system in drive 0)
    f  check the file system (first insert any file system diskette)
    l  check and list file system (first insert any file system diskette)
    m  make an (empty) file system (first insert blank, formatted diskette)
    h  check hard disk file system

Hit C-a c
# QEMU 3.1.0 monitor - type 'help' for more information
(qemu) change floppy0 floppy_disk2
Hit C-a c
(qemu)
f
Checking diskette.  Answer questions with y or n.  Then hit RETURN

Checking zone map
Checking inode map
Checking inode list

blocksize =  1024        zonesize  =  1024

    20    Regular files
     8    Directories
    13    Block special files
     3    Character special files
    51    Free inodes
    53    Free zones

Hit key as follows:

    =  start MINIX (root file system in drive 0)
    :

成功である。上のやつは、フロッピーディスクの2枚目(ルートファイルシステム)をチェックしたものである。どんなファイルが配置されてるかはlコマンドで確認出来るぞ。

じゃ本番

qemu-system-i386 -fda boot -monitor stdio

floppyを入れ替えるchangeってqemuのコマンドを画面切り替え、Ctl-Alt-1(or 2)して入力するのが面倒。なんで、モニター画面を常に別に出しておく。

それから、突然bootなんてのが出てきたけど、これはREADME_1.1に

Disk 1: Boot Disk
Disk 2: Root File System
Disk 3: /usr
Disk 4: /user

こんな説明が有ったので、分かり易いように、名前を変えている。

で、= を押しても、残念ながらminixが起動してきーせん。諦めて、kernelの起動コードを眺めている。最初の部分は、アセンブラーコードになってる。

kernel/MINIX/mpx88.s

.text
begtext:
|*===========================================================================*
|*                              MINIX                                        *
|*===========================================================================*
MINIX:                          | this is the entry point for the MINIX kernel.
        jmp M.0                 | skip over the next few bytes
        .word 0,0               | build puts DS at kernel text address 4
M.0:    cli                     | disable interrupts
        mov ax,cs               | set up segment registers
        mov ds,ax               | set up ds
        mov ax,4                | build has loaded this word with ds value
        mov ds,ax               | ds now contains proper value
        mov ss,ax               | ss now contains proper value
        mov _scan_code,bx       | save scan code for '=' key from bootstrap
        mov sp,#_k_stack        | set sp to point to the top of the
        add sp,#K_STACK_BYTES   |       kernel stack

        call _main              | start the main program of MINIX
M.1:    jmp M.1                 | this should never be executed

kernel/C86/mpx88.asm これ参考値でMS-DOS用。

$main:
Minix:                          ; this is the entry point for the Minix kernel.
        jmp short M0            ; skip over the next word(s)
        ORG 4                   ; build writes the ds value at text address 4
ker_ds  DW  dgroup              ; this word will contain kernel's ds value
                                ; and it forces relocation for dos2out
     M0:cli                     ; disable interrupts
        mov ax,cs               ; set up segment registers
        mov ds,ax               ; set up ds
        mov ax,cs:ker_ds        ; build has loaded this word with ds value
        mov ds,ax               ; ds now contains proper value
        mov ss,ax               ; ss now contains proper value
        mov dgroup:scan_cod,bx  ; save scan code for '=' key from bootstrap
        mov sp,offset dgroup:k_stack    ; set sp to point to the top of the
        add sp,K_STACK_BYTES            ; kernel stack
        call main               ; start the main program of Minix

     M1:jmp M1                  ; this should never be executed

fsck.c/main

                c = getc();
                command = c & 0xFF;
                switch (command) {
                  :
                case '=': return((c >> 8) & 0xFF);

これで、元に戻る? bootblkへか? いや違うかtools/MINIX/fsck1.sあたりかな。

        call    _main
        mov     bx,ax           | put scan code for '=' in bx
        cli
        mov     dx,#0x60
        mov     ds,dx
        mov     es,dx
        mov     ss,dx
        jmpi    0,0x60          | jmp to kernel

MS-DOSのコードにヒントが無いか?

MINIX   SEGMENT AT 60h          ; This is where Minix is loaded
kernel  label byte              ; absolute address 0000:1536d = 0060:0000h
MINIX   ENDS

        call    main
        mov     bx,ax           ; put scan code for '=' in bx
        cli
        mov     dx,60h
        mov     ds,dx
        mov     es,dx
        mov     ss,dx
        jmp     far ptr kernel          ; direct jmp to kernel & start Minix

qemuのmonitorを使って、regsterの確認

(qemu) info registers
EAX=00000700 EBX=00000016 ECX=00000000 EDX=000003da
ESI=00000000 EDI=00000002 EBP=000062ac ESP=000062a0
EIP=0000449c EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0000 00000000 0000ffff 00009300
CS =0060 00000600 0000ffff 00009b00
SS =0060 00000600 0000ffff 00009300
DS =0060 00000600 0000ffff 00009300
FS =0000 00000000 0000ffff 00009300
GS =0000 00000000 0000ffff 00009300
LDT=0000 00000000 0000ffff 00008200
TR =0000 00000000 0000ffff 00008b00
GDT=     00000000 00000000
IDT=     00000000 000003ff
 :

csやdsが指定した値になってるので、一応kernelは走っているっぽい。分かるのはここまでだなあ。残念ながらね。

fsdb

つまらないのでウダウダしてたら、fsdb なんて言う楽しそうなコマンドを見つけた。

ob# fsdb -f /dev/rvnd0c
** /dev/rvnd0c
** File system is already clean
Editing file system `/dev/rvnd0c'
Last Mounted on /mnt/ffs
current inode: directory
I=2 MODE=40775 SIZE=512
        MTIME=Apr 13 09:00:56 2020 [847228541 nsec]
        CTIME=Apr 13 09:00:56 2020 [847228541 nsec]
        ATIME=Apr 13 08:42:56 2020 [419367358 nsec]
OWNER=root GRP=wheel LINKCNT=2 FLAGS=0 BLKCNT=4 GEN=9b7cfeb
fsdb (inum: 2)> ls
slot 0 ino 2 reclen 12: directory, `.'
slot 1 ino 2 reclen 12: directory, `..'
slot 2 ino 3 reclen 488: regular, `aa'
fsdb (inum: 2)>

どうやって使うかはman嫁。

from 6845

kernelが出すメッセージを拝めないのでソースを拝んでいたんだ。bootのメッセージはBIOSに依頼してた。それから、= キーの値をカーネルまで渡しているのは、キーコードが異なるマシン(オリベッティ製のPC)があるので、その判定をやってるためだった。

それはいいんだけど、qemuのコンソール(平たく言うとCRT)は、ビデオタイプなのね。で、そのコントロールをやってる石が 6845っていうものらしい。元ハード屋の性で、データシートを見たい。そんな事で、検索してたら、

【2000行弱!】x86用自作カーネルの紹介

自作OS(OS5)のまとめ

こんな面白いページにたどり着いたぞ。