jslinux向けに最新カーネル3.8.5をビルド

ネタとしては古いですが、jslinuxについていろいろと調べていました。

これは、QEMUの作者でもある Fabrice Bellard 氏が、JavaScriptで動作するPCエミュレータを作成し、その上でLinuxを動作させているものです。


こちらでは、Linux 2.6.20が動作しています。
今回は、最新のLinux 3.8.5をこのPCエミュレータ向けにビルドして動作させてみました。

作業場所の準備

前提として、ウェブサーバが動作しているものとします。
なお、ここでの説明では、ローカルにウェブサーバが動作していることを想定し、

作業ディレクト ~/jslinux/
URL http://localhost/jslinux/

のように、準備できているものとします。

jslinux動作環境の構築

こちらの記事で紹介されている
「ソースとディスクイメージの取得」
シェルスクリプトを実行し、取得したものを

~/jslinux/

に配置してください。


そして、

こちらのページの「index.html」を、

~/jslinux/index.html

として配置してください。


コマンドライン上で操作を行う場合は、以下の様になります。
(シェルスクリプトは「~/jslinux/dl_batch.sh」に配置されているとする。)

$ cd ~/jslinux
$ chmod u+x dl_batch.sh
$ ./dl_batch.sh
$ wget http://bellard.org/jslinux/


なお、こちらのシェルスクリプトで、
hda000000000.bin 〜 hda000000911.bin
までの間のいくつかのファイルはダウンロードもれが発生する場合があります。

#!/bin/bash
host=http://bellard.org/jslinux/

# wget $host/cpux86-ta.js
# wget $host/cpux86.js
# wget $host/jslinux.js
# wget $host/term.js
# wget $host/utils.js

# wget $host/linuxstart.bin
# wget $host/vmlinux-2.6.20.bin

i=0
while [ $i -le 999 ]; do
        hda=$(printf 'hda%09d.bin' $i)
    if [ ! -f $hda ]; then
        wget $host/$hda &
    fi

    i=$(( $i + 1 ))
done

のように、既にダウンロード済みの箇所はコメントアウトして、
何度か実行する必要があります。
(私の場合は、4度程繰り返し実行しました。)


「*.bin」の不足に関しては、
試しにブラウザで

http://localhost/jslinux/

へアクセスしてみて、
ブラウザのJavaScriptデバッグ機能(例、ChromeJavaScriptコンソール)で
「〜が存在しません」という旨のエラーメッセージから探していく方法でも構いません。


すべてのファイルが揃っていれば、

http://localhost/jslinux/

へアクセスすると、ブラウザ上でLinuxが動作することを確認できるはずです。

jslinux向けカーネルビルドに必要なファイルの準備

こちらのページから「linuxstart-20120111.tar.gz」をダウンロードし、

こちらのページから「linux-3.8.5.tar.xz」をダウンロードしてください。


それぞれを展開し、以下の構成となるように配置してください。
「linuxstart-20120111.tar.gz」は、展開すると
最上位のディレクトリは「tmp」なので注意してください。

  • ~/make_jskernel/
    • linuxstart-20120111/
    • linux-3.8.5/


なお、コマンドでの操作は以下の様になります。
(ダウンロードした2つのファイルはホームディレクトリに配置されているものとします。
また、作業ディレクトリは「~/make_jskernel/」とします。)

$ cd
$ tar zxf linuxstart-20120111.tar.gz
$ tar Jxf linux-3.8.5.tar.xz
$ mkdir make_jskernel/
$ cp -r tmp/linuxstart-20120111 make_jskernel/
$ cp -r linux-3.8.5 make_jskernel/
$ rm -rf linuxstart-20120111.tar.gz tmp/ linux-3.8.5.tar.xz linux-3.8.5/

パッチの適用

~/make_jskernel/linuxstart-20120111/

に、「patch_linux-2.6.20」というファイルがあります。


パッチの形式になっているのですが、2.6.20のカーネルに対してのパッチなので、
「3.8.5」への適用の際には、手作業で適用作業を行います。


といっても、パッチファイルの中身は単なるdiffの結果を羅列したテキストファイルで、
今回の場合は、作業量も多くないので、30分もかからないくらいで終わります。


修正、あるいは追加が必要なファイルは以下のものです。

  • linux-3.8.5/drivers/char/Kconfig (修正)
  • linux-3.8.5/drivers/char/Makefile (修正)
  • linux-3.8.5/drivers/char/jsclipboard.c (追加)
  • linux-3.8.5/drivers/tty/serial/8250/8250.c (修正)
  • linux-3.8.5/drivers/ide/ide-probe.c (修正)
linux-3.8.5/drivers/char/Kconfig

596行目以降に関して、以下の様に修正してください。

config TILE_SROM
	bool "Character-device access via hypervisor to the Tilera SPI ROM"
	depends on TILE
	default y
	---help---
	  This device provides character-level read-write access
	  to the SROM, typically via the "0", "1", and "2" devices
	  in /dev/srom/.  The Tilera hypervisor makes the flash
	  device appear much like a simple EEPROM, and knows
	  how to partition a single ROM for multiple purposes.

===== ここから =====
config JSCLIPBOARD
	tristate "Javascript clipboard support (JS/Linux device)"
	default n
	help
	  Javascript clipboard support for JS/Linux
===== ここまでを追加 =====

endmenu
linux-3.8.5/drivers/char/Makefile

56行目以降に関して、以下の様に修正してください。

obj-$(CONFIG_HANGCHECK_TIMER)	+= hangcheck-timer.o
obj-$(CONFIG_TCG_TPM)		+= tpm/
obj-$(CONFIG_JSCLIPBOARD)	+= jsclipboard.o   <= この行を追加

obj-$(CONFIG_PS3_FLASH)		+= ps3flash.o
linux-3.8.5/drivers/char/jsclipboard.c

以下の内容のファイルを追加してください。


なお、パッチファイルの方では25行目に

#include

が示されていますが、これはカーネルバージョンの3.8.5において複数に分割されて存在しないものなので、
この記述は削除しました。


参考:

/* 
   JS clipboard support for JS/Linux
   (c) 2011 Fabrice Bellard
*/
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/miscdevice.h>
#include <linux/ioport.h>
#include <linux/fcntl.h>
#include <linux/mc146818rtc.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/spinlock.h>
#include <linux/sysctl.h>
#include <linux/wait.h>
#include <linux/bcd.h>
#include <linux/delay.h>

#include <asm/current.h>
#include <asm/uaccess.h>

#define JSCLIPBOARD_MINOR 231

#define JSCLIPBOARD_PORT 0x3c0

static int io_port = JSCLIPBOARD_PORT;
static int minor = JSCLIPBOARD_MINOR;
static struct semaphore open_sem;
static int need_cache_sync;

module_param(io_port, int, 0);
MODULE_PARM_DESC(io_port, "IO port");

module_param(minor, int, 0);
MODULE_PARM_DESC(minor, "minor number");

static ssize_t jsclipboard_read(struct file *file, char __user *buf,
                                size_t count1, loff_t *ppos)
{
        uint32_t pos, total_length, v;
        uint8_t b;
        size_t count, l;
        
        /* set read position */
        pos = *ppos;
        outl(pos, io_port + 4);
        total_length = inl(io_port + 0);
        
        if (!access_ok(VERIFY_WRITE, buf, count1))
                return -EFAULT;
        
        if (pos < total_length) 
                l = total_length - pos;
        else
                l = 0;
        if (count1 > l)
                count1 = l;
        count = count1;
        while (count >= 4) {
                v = inl(io_port + 8);
                if (__put_user(v, (uint32_t *)buf))
                        return -EFAULT;
                buf += 4;
                count -= 4;
        }
        
        while (count != 0) {
                b = inb(io_port + 8);
                if (__put_user(b, buf))
                        return -EFAULT;
                buf++;
                count--;
        }

        *ppos = pos + count1;

        return count1;
}

static ssize_t jsclipboard_write(struct file *file, const char *buf, 
                                 size_t count1, loff_t *ppos)
{
        size_t count;
        uint8_t b;
        uint32_t v;

        if (!access_ok(VERIFY_READ, buf, count1))
                return -EFAULT;
        if (*ppos == 0) {
                /* flush clipboard */
                outl(0, io_port);
        }

        need_cache_sync = 1;

        count = count1;
        while (count >= 4) {
                if (__get_user(v, (uint32_t *)buf))
                        return -EFAULT;
                outl(v, io_port + 8);
                buf += 4;
                count -= 4;
        }

        while (count != 0) {
                if (__get_user(b, buf))
                        return -EFAULT;
                outb(b, io_port + 8);
                buf++;
                count--;
        }
        *ppos += count1;
        return count1;
}

static int jsclipboard_open(struct inode *inode, struct file *file)
{
	if (down_trylock(&open_sem))
		return -EBUSY;
        need_cache_sync = 0;
	return 0;
}

static int jsclipboard_release(struct inode *inode, struct file *file)
{
        if (need_cache_sync) {
                outl(0, io_port + 12);
        }
	up(&open_sem);
	return 0;
}

static const struct file_operations jsclipboard_fops = {
	.owner		= THIS_MODULE,
	.read		= jsclipboard_read,
	.write		= jsclipboard_write,
	.open		= jsclipboard_open,
        .release        = jsclipboard_release,
};

static struct miscdevice jsclipboard_dev = {
	.minor		= JSCLIPBOARD_MINOR,
	.name		= "jsclipboard",
	.fops		= &jsclipboard_fops,
};

static int __init jsclipboard_init(void)
{
        if (!request_region(io_port, 16, "jsclipboard")) 
                return -ENODEV;
	sema_init(&open_sem, 1);
	if (misc_register(&jsclipboard_dev)) {
                return -ENODEV;
	}
	printk(KERN_INFO "JS clipboard: I/O at 0x%04x\n", io_port);
	return 0;
}

static void __exit jsclipboard_exit (void)
{
	misc_deregister(&jsclipboard_dev);
        release_region(io_port, 16);
}

module_init(jsclipboard_init);
module_exit(jsclipboard_exit);

MODULE_AUTHOR("Fabrice Bellard");
MODULE_LICENSE("GPL");
linux-3.8.5/drivers/tty/serial/8250/8250.c

パッチファイルでは、

linux-2.6.20/drivers/serial/8250.c

となっていましたが、3.8.5においては

linux-3.8.5/drivers/tty/serial/8250/8250.c

に対応するファイルが存在するため、こちらを修正します。


77行目以降に関して、以下の様に修正してください。

#if 0
#define DEBUG_INTR(fmt...)	printk(fmt)
#else
#define DEBUG_INTR(fmt...)	do { } while (0)
#endif

===== ここから =====
//#define PASS_LIMIT	512
#define PASS_LIMIT	(256 * 100)
===== ここまでの様に修正 =====

#define BOTH_EMPTY 	(UART_LSR_TEMT | UART_LSR_THRE)
linux-3.8.5/drivers/ide/ide-probe.c

このファイルの内容自体が、2.6.20から3.8.5にかけて大きく変わっているため、
パッチファイルが意図している修正を全て満たせているかは分かりませんが、
以下の様に修正して、動作を確認できています。


なお、パッチファイルのコメントにもあるように、
必須な修正ではなく、より速くするための修正であるので、
動作が不安定であると感じたならば元に戻した方がよいかもしれません。


1021行目以降に関して、以下の様に修正してください。

static void ide_port_init_devices(ide_hwif_t *hwif)
{
	const struct ide_port_ops *port_ops = hwif->port_ops;
	ide_drive_t *drive;
	int i;

	ide_port_for_each_dev(i, drive, hwif) {
		drive->dn = i + hwif->channel * 2;

===== ここから =====
		/* force 32 bit I/O so that boot time is a little faster */
		//if (hwif->host_flags & IDE_HFLAG_IO_32BIT)
			drive->io_32bit = 1;
===== ここまでの様に修正 =====
		if (hwif->host_flags & IDE_HFLAG_NO_IO_32BIT)
			drive->dev_flags |= IDE_DFLAG_NO_IO_32BIT;
		if (hwif->host_flags & IDE_HFLAG_UNMASK_IRQS)
			drive->dev_flags |= IDE_DFLAG_UNMASK;
		if (hwif->host_flags & IDE_HFLAG_NO_UNMASK_IRQS)
			drive->dev_flags |= IDE_DFLAG_NO_UNMASK;

		drive->pio_mode = XFER_PIO_0;

		if (port_ops && port_ops->init_dev)
			port_ops->init_dev(drive);
	}
}


ひとまず、ここまで。


続きは、後ほど追記か、別記事にて作成いたします。


つづきは、こちらに作成しました。