コグノスケ


link 未来から過去へ表示(*)  link 過去から未来へ表示

link もっと前
2024年10月2日 >>> 2024年9月19日
link もっと後

2024年10月2日

VirtualBoxでxrdpのエラーを再現できるか挑戦

目次: Linux

昨日(2024年10月1日の日記参照)のUbuntu 22とxrdpの組み合わせで起きるエラーですが、VirtualBox 7.0.18で再現できるかやってみました。グラフィクスはVMSVGAを選択しています。VMSVGAは/dev/driの下にcard0とrenderD128が生成されるようです。ちなみにgdm3は終了させてxrdpのみ起動しています。

ちなみに結論から言っておくと再現しません。以下が通常時のログです。正常に画面が表示されます。

VirtualBox&Ubuntu 22.04 LTSのgnome-session-binaryのログ
gnome-session-binary[2774]: DEBUG(+): Enabling debugging
gnome-session-binary[2774]: GLib-GIO-DEBUG(+): _g_io_module_get_default: Found default implementation dconf (DConfSettingsBackend) for ‘gsettings-backend’

ログにはデバッグ有効であることと、libEGLが何かしら見つけて反応しています。それ以外は特に何も出ません。

次にcard0とrenderD128をリネームしてアクセスできないようにして試しました。しかし正常に画面が表示されます。えぇー?ログは下記のようになりました。

card0とrenderD128をリネームした時のログ
gnome-session-binary[4319]: DEBUG(+): Enabling debugging
gnome-session-check-accelerated: GL Helper exited with code 512
libEGL warning: DRI2: failed to authenticate
gnome-session-check-accelerated: GLES Helper exited with code 512
gnome-session-binary[4319]: GLib-GIO-DEBUG(+): _g_io_module_get_default: Found default implementation dconf (DConfSettingsBackend) for ‘gsettings-backend’

AMDのGPUでも見かけたfailed to authenticateが出ています。が、エラーは無視されるんでしょうか?謎の動きですね。

編集者:すずき(2024/10/05 15:08)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2024年10月1日

Ubuntu 22.04のxrdpに接続できない病

目次: Linux

WindowsからUbuntu 22.04 LTSのxrdpに接続すると真っ黒な画面しか出ず、すぐに接続が切断されてしまう問題に遭遇しました。どこでクラッシュしているか調べるため、xrdpがGNOMEを起動するところまでを追いかけると下記のようになっていました。

xrdpがXsessionを起動するまでの呼び出し経路
/etc/xrdp/startwm.sh
  exec /bin/sh /etc/X11/Xsession
    /etc/X11/Xsession.d/99x11-common_start
      /usr/bin/ssh-agent /usr/bin/im-launch x-session-manager
        /usr/bin/x-session-manager
          /usr/libexec/gnome-session-binary

スクリプトx-session-managerを書き換えてgnome-session-binaryの引数に--debugを足すと、GNOMEはより詳細なメッセージを出力します。メッセージはホームディレクトリの.xsession-errorsに記録されます。GNOMEのエラーメッセージは下記です。

GNOMEのエラーメッセージ
** (gnome-session-check-accelerated-gles-helper:3301100): WARNING **: 13:50:04.884: eglInitialize() failed
gnome-session-check-accelerated: GLES Helper exited with code 256
gnome-session-binary[3300977]: DEBUG(+): hardware acceleration check failed: Child process exited with code 1
gnome-session-binary[3300977]: GLib-DEBUG(+): setenv()/putenv() are not thread-safe and should not be used after threads are created
gnome-session-binary[3300977]: GLib-DEBUG(+): posix_spawn avoided (fd close requested)
gnome-session-is-accelerated: No hardware 3D support.
gnome-session-check-accelerated: GL Helper exited with code 256    ★★ここでエラーが発生している
amdgpu_device_initialize: amdgpu_get_auth (1) failed (-1)
amdgpu_device_initialize: amdgpu_get_auth (1) failed (-1)

** (gnome-session-check-accelerated-gles-helper:3301174): WARNING **: 13:50:09.927: eglInitialize() failed
gnome-session-check-accelerated: GLES Helper exited with code 256
gnome-session-binary[3300977]: WARNING: software acceleration check failed: Child process exited with code 1
gnome-session-binary[3300977]: CRITICAL: We failed, but the fail whale is dead. Sorry....

エラーメッセージ曰くamdgpu_get_auth()が失敗しています。関数名から推測するにAMDのGPUが装着されているマシンでしか発生しないエラーなのかもしれません。この関数は何者なのかDRMのソースコード(Mesa/libdrmのソースコードリポジトリへのリンク)を見ると、

libdrmのソースコード

// drm/amdgpu/amdgpu_device.c

/**
* Get the authenticated form fd,
*
* \param   fd   - \c [in]  File descriptor for AMD GPU device
* \param   auth - \c [out] Pointer to output the fd is authenticated or not
*                          A render node fd, output auth = 0
*                          A legacy fd, get the authenticated for compatibility root
*
* \return   0 on success\n
*          >0 - AMD specific error code\n
*          <0 - Negative POSIX Error code
*/
static int amdgpu_get_auth(int fd, int *auth)
{
	int r = 0;
	drm_client_t client = {};

	if (drmGetNodeTypeFromFd(fd) == DRM_NODE_RENDER)
		*auth = 0;
	else {
		client.idx = 0;
		r = drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client);    //★★エラーを返すのはこの関数だけ★★
		if (!r)
			*auth = client.auth;
	}
	return r;
}


// drm/xf86drm.c

/**
 * Call ioctl, restarting if it is interrupted
 */
drm_public int
drmIoctl(int fd, unsigned long request, void *arg)
{
    int ret;

    do {
        ret = ioctl(fd, request, arg);    //★★drmIoctl()はioctl()が返すエラーをそのまま返す★★
    } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
    return ret;
}

ソースコードから推測するにグラフィクス系のデバイスファイルにioctl()しようとして失敗しているものと思われます。

XのグラフィックスはDRI(Direct Rendering Infrastructure)と呼ばれるインタフェースを経由してGPUを使用します。Xとカーネルの間にはlibDRMがおり、libDRMはLinuxカーネルのDRM(Direct Rendering Manager)を使用してGPUにアクセスします。DRMのデバイスファイルは/dev/driディレクトリの下にありますが、名前がDRIだったりDRMだったりして謎ですね。グラフィクス周りはあまり詳しくなくて理由はわかりません……。

DRMのデバイスファイルの例
# ls /dev/dri/* -la

crw-rw-rw-+ 1 root video  226,   0  4月 30 15:00 /dev/dri/card0
crw-rw-rw-+ 1 root render 226, 128  4月 30 15:00 /dev/dri/renderD128

上記のようにキャラクタデバイス/dev/dri/card0と/dev/dri/renderD128のパーミッションを0666にしたところエラーが出なくなりました。今回はこの2つのデバイスファイルで解決しましたが、他のデバイスファイルにもアクセスしていた場合はさらに調査が必要かもしれません。グラフィクス系のエラーは簡単に調べる方法がないのが辛いですね。

ちなみにこの症状はQEMUだと再現しません。card0のパーミッションを0000にするとlibEGLがエラーになるのですが、なぜかGNOMEはエラーを無視して起動してしまいます。AMDのときだけなんで止まるんでしょうか。いまいち釈然としません……。

編集者:すずき(2024/10/05 15:07)

コメント一覧

  • hdkさん(2024/10/03 08:30)
    おー、面白いですね。xrdpはすでに立ち上がっているVNCサーバーにつなぐ設定しかしたことがなくて、startwm.shなんてスクリプトがあったとは...
    この前WaylandのWestonを少し触ったんですが(ちなみにWestonにもRDPやVNCを提供する機能もあります)、その時にrendererにCPUを使うかGPUを使うかの選択肢がありました。Container上でXwaylandとXアプリケーションを走らせてホスト側Weston上に出すみたいなことをしたんですけど、GPUを使う設定だとXwaylandがDRMデバイスを探してしまってcontainerからアクセスできないのでエラーになるというのがありました。
    それで、QEMUだと再現しないというのは、まともなハードウェアアクセラレーションがないのでソフトウェアレンダリングになっているのかな、と思いました。
    /dev/driはkvmと同様にローカルのログインユーザーにはudevのuaccessでアクセス権が与えられていますね。
  • すずきさん(2024/10/03 10:12)
    私は逆にVNCサーバーに繋ぐ使い方をしたことがなくて、違いがわかってないです。あと今回調べて初めて構造を知ったので、正しいのか若干不安です。
    Westonは触ったことないですねえ。しかもコンテナ内でもないから普通に動作してほしいところです。

    GNOMEがハードウェアレンダリングかソフトウェアレンダリングかどちらを選択したのか確認しなかったですね。ログに出るかな?
    パーミッションに関してはおっしゃる通りで/dev/driは通常パーミッションの問題は発生しないですが、なぜか今回は変な現象が発生しました。AMDのGPUだと何かあるのかなあ……?
  • hdkさん(2024/10/03 19:05)
    GNOMEをお使いでしたら今はWaylandにも対応していますから、Westonと同じようにRDPのバックエンドを選べてもよさそうです。

    パーミッションは、AMDだからというよりは、たぶんローカルでログインした扱いになっていないんじゃないかと思います。uaccessの設定は端末の眼の前で直接ログインした時にはアクセス権が付与されるんですが、それ以外のSSHとかVNCとかでは付与されないものです。昔、大学の共用計算機システムみたいなところで、光学ドライブのパーミッションが0666になっていて、人が使っているところにリモートログインして勝手にejectを実行する、なんて遊びがありましたが、そういうのができないように、今はuaccessで管理されるみたいですね。
  • すずきさん(2024/10/06 03:41)
    xrdpで十分動作しているので、Waylandにはそこまでこだわってないんですが、時代はWaylandなのかなあ。

    uaccess知らなかったので少し調べてみたら、
    TAG+="uaccess"
    をルールに追加するとpam-systemdからsystemd-logindに依頼が行ってACLでパーミッションが設定される、なんて仕組みがあるんですね。なかなか複雑だなあ……。
open/close この記事にコメントする



2024年9月28日

TAS動画をニコニコ動画にアップロードできない

クラッキングでぶっ壊されてしまったニコニコ動画が復活し、シン・ニコニコ動画になって帰ってきました。いちユーザーとしては嬉しい気分でいっぱいです。

しかし前と比べて困ったことが起きていて、BizHawkで出力した動画をシン・ニコニコ動画にアップロードしようとすると「この動画の映像形式には対応していません」とエラーが出てしまって投稿できません。試行錯誤の末、解決方法を見つけたのでメモしておきます。

端的に言えば原因はピクセルフォーマットでした。BizHawkは特に何も言わないとYUV444で出力しますが、ニコニコ動画はYUV420でないと受け付けてくれないようです。どこにもそんな制約は書いていないため、仕様か?バグか?どちらともわかりません。

YUV420にする方法ですけども、BizHawkの出力設定を[Custom]にして、下記のようにピクセルフォーマットを明示的に指定すればYUV420で出力してくれました。

BizHawkの[Custom]動画出力設定の例
-c:a aac -c:v libx264 -preset ultrafast -pix_fmt yuv420p -f mp4

もしすでにYUV444で出力済みの動画ならば、ffmpegを使って再エンコードすれば良いです。

ピクセルフォーマットYUV420で再エンコード
$ ffmpeg -i input.mp4 \
    -vcodec libx264 -vb 2048000 -r 60 -s 1280x720 -pix_fmt yuv420p \
    -acodec aac -ar 44100 -ab 192000 output.mp4

動画ビットレート(-vb)、フレームレート(-r)、動画サイズ(-s)は元の動画に応じて調整してください。

編集者:すずき(2024/10/03 01:07)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2024年9月24日

OpenSBIを調べる - CPUの列挙

目次: Linux

以前、OpenSBIがRISC-V CPUの拡張機能をどのように認識し有効にするか調べました。今回はどのようにCPUの数を認識するか調べます。OpenSBIのプラットフォームは今まで同様にgenericを使います。

実はそんなに難しくなく、デバイスツリーの/cpuノードを読みに行くだけのようです。/cpuノードの例としてQEMU virtマシン、4CPUで起動したときにQEMUが生成するデバイスツリーを下記に示します。長いのでCPU_2, 3は省略しています。名前やラベル、regが2や3になるだけです。

デバイスツリーのCPUノードの例
/ {
	cpus {
		#address-cells = <1>;
		#size-cells = <0>;
		timebase-frequency = <10000000>;

		cpu0: cpu@0 {
			compatible = "riscv";
			reg = <0>;
			device_type = "cpu";
			riscv,cbop-block-size = <64>;
			riscv,cboz-block-size = <64>;
			riscv,cbom-block-size = <64>;
			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "h",
				"zic64b", "zicbom", "zicbop", "zicboz",
				"ziccamoa", "ziccif", "zicclsm", "ziccrse",
				"zicntr", "zicsr", "zifencei", "zihintntl",
				"zihintpause", "zihpm", "za64rs", "zawrs",
				"zfa", "zca", "zcd", "zba", "zbb", "zbc", "zbs",
				"ssccptr", "sscounterenw", "sstc", "sstvala",
				"sstvecd", "svadu";
			riscv,isa-base = "rv64i";
			riscv,isa = "rv64imafdch_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_zicclsm_ziccrse_zicntr_zicsr_zifencei_zihintntl_zihintpause_zihpm_za64rs_zawrs_zfa_zca_zcd_zba_zbb_zbc_zbs_ssccptr_sscounterenw_sstc_sstvala_sstvecd_svadu";
			mmu-type = "riscv,sv57";

			status = "okay";

			cpu0_intc: interrupt-controller {
				compatible = "riscv,cpu-intc";
				interrupt-controller;
				#interrupt-cells = <1>;
			};
		};

		cpu1: cpu@1 {
			compatible = "riscv";
			reg = <1>;
			device_type = "cpu";
			riscv,cbop-block-size = <64>;
			riscv,cboz-block-size = <64>;
			riscv,cbom-block-size = <64>;
			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "h",
				"zic64b", "zicbom", "zicbop", "zicboz",
				"ziccamoa", "ziccif", "zicclsm", "ziccrse",
				"zicntr", "zicsr", "zifencei", "zihintntl",
				"zihintpause", "zihpm", "za64rs", "zawrs",
				"zfa", "zca", "zcd", "zba", "zbb", "zbc", "zbs",
				"ssccptr", "sscounterenw", "sstc", "sstvala",
				"sstvecd", "svadu";
			riscv,isa-base = "rv64i";
			riscv,isa = "rv64imafdch_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_zicclsm_ziccrse_zicntr_zicsr_zifencei_zihintntl_zihintpause_zihpm_za64rs_zawrs_zfa_zca_zcd_zba_zbb_zbc_zbs_ssccptr_sscounterenw_sstc_sstvala_sstvecd_svadu";
			mmu-type = "riscv,sv57";

			status = "okay";

			cpu1_intc: interrupt-controller {
				compatible = "riscv,cpu-intc";
				interrupt-controller;
				#interrupt-cells = <1>;
			};
		};

		cpu2: cpu@2 {
			/* 省略 */
		};

		cpu3: cpu@3 {
			/* 省略 */
		};

OpenSBIがCPU数を確認するコードは下記のようになっています。

OpenSBIがCPU数を確認するコード

// opensbi/platform/generic/platform.c

unsigned long fw_platform_init(unsigned long arg0, unsigned long arg1,
				unsigned long arg2, unsigned long arg3,
				unsigned long arg4)
{
	const char *model;
	void *fdt = (void *)arg1;    //★★デバイスツリーのアドレス、レジスタa1を使ってOpenSBIに渡す★★
	u32 hartid, hart_count = 0;
	int rc, root_offset, cpus_offset, cpu_offset, len;

	//...

	cpus_offset = fdt_path_offset(fdt, "/cpus");
	if (cpus_offset < 0)
		goto fail;

	fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
		//★★device_typeがcpu、regプロパティに値が入っていれば、CPUのノードとみなす★★
		rc = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
		if (rc)
			continue;

		if (SBI_HARTMASK_MAX_BITS <= hartid)
			continue;

		//★★statusプロパティがokかokayなら有効なCPUとみなす★★
		if (!fdt_node_is_enabled(fdt, cpu_offset))
			continue;

		//★★ハート数を1つ増やす★★
		//★★hartidは連番とは限らないため、hartindexとhartidの対応表を作る★★
		generic_hart_index2id[hart_count++] = hartid;
	}

	//★★platform領域に記録する★★
	platform.hart_count = hart_count;
	platform.heap_size = fw_platform_calculate_heap_size(hart_count);
	platform_has_mlevel_imsic = fdt_check_imsic_mlevel(fdt);

デバイスツリー(正確にはFDT: flattened device tree)の/cpuノードを見て、子ノードがCPUの定義であり、有効ならばhart_countを+1するシンプルなコードです。hartidは連番とは限らないため、hartindex(0からCPU数 - 1までの連番)とhartidの対応表generic_hart_index2id[]も同時に作ります。

無効なCPUはどうなるか?

無効なCPUの扱いも見ておきます。先程のコードからわかる通りstatus = "disabled"つまり無効なCPUの場合は、hartindexとhartidの対応表(platform.hart_index2id[])にhartidが載りません。例としてQEMUにてCPU 4つで起動し、デバイスツリーでCPU 2だけstatus = "disabled"にしたときのhartindexとhartidの対応表をダンプします。

4CPU, CPU2だけ無効のときのhartindexとhartidの対応表
(gdb) p platform
$11 = {opensbi_version = 65541, platform_version = 1,
  name = "riscv-virtio,qemo", '\000' <repeats 46 times>, features = 2,
  hart_count = 3, hart_stack_size = 8192, heap_size = 39936, reserved = 0,
  platform_ops_addr = 2148010200, firmware_context = 0,
  hart_index2id = 0x80083700 <generic_hart_index2id>}

(gdb) p generic_hart_index2id
$15 = {0, 1, 3, 0 <repeats 125 times>}

全CPUが有効ならば0, 1, 2, 3となりますが、CPU 2が無効なので0, 1, 3となっていることがわかります。

次にメインCPUがサブCPUを起こしに行くコードを見ます。アセンブラなので若干分かりづらいですが、hartindexとhartidの対応表に自CPUのhartidが登録されていればCPUを起動し、登録されていない場合はCPUを起動しません。

OpenSBIがサブCPUを起こす処理

// opensbi/firmware/fw_base.S

_fdt_reloc_done:
	//★★メインCPUはこちら★★
	//★★初期化処理が終わるとここに到達する★★
	//★★_boot_statusにBOOT_STATUS_BOOT_HART_DONEを書き込むとサブCPU側がループを抜ける★★
	/* mark boot hart done */
	li	t0, BOOT_STATUS_BOOT_HART_DONE
	lla	t1, _boot_status
	fence	rw, rw
	REG_S	t0, 0(t1)
	j	_start_warm

	//★★サブCPUはこちら★★
	//★★_boot_statusを読みながらループで待っている★★
	/* waiting for boot hart to be done (_boot_status == 2) */
_wait_for_boot_hart:
	li	t0, BOOT_STATUS_BOOT_HART_DONE
	lla	t1, _boot_status
	REG_L	t1, 0(t1)
	/* Reduce the bus traffic so that boot hart may proceed faster */
	div	t2, t2, zero
	div	t2, t2, zero
	div	t2, t2, zero
	bne	t0, t1, _wait_for_boot_hart

_start_warm:
	/* Reset all registers except ra, a0, a1, a2, a3 and a4 for non-boot HART */
	li	ra, 0
	call	_reset_regs

	/* Disable all interrupts */
	csrw	CSR_MIE, zero

	//★★platform.hart_index2idを見て、hartidと一致する要素があるか確かめる★★
	/* Find HART count and HART stack size */
	lla	a4, platform
#if __riscv_xlen > 32
	lwu	s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
	lwu	s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
#else
	lw	s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
	lw	s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
#endif
	//★★s9はplatform.hart_index2id[0]のアドレス★★
	REG_L	s9, SBI_PLATFORM_HART_INDEX2ID_OFFSET(a4)

	/* Find HART id */
	csrr	s6, CSR_MHARTID

	//★★platform.hart_index2idがNULLだったら処理を止める★★
	/* Find HART index */
	beqz	s9, 3f
	li	a4, 0

	//★★a4 = hartindex
	//★★a5 = platform.hart_index2id[hartindex]の値(hartindexに対応するhartid)
	//★★s6 = CPUのhartid
	//★★s7 = hart数
	//★★s9 = platform.hart_index2id[hartindex]のアドレス
1:
#if __riscv_xlen > 32
	lwu	a5, (s9)
#else
	lw	a5, (s9)
#endif
	//★★hartidとplatform.hart_index2id[n]が一致していたら、ループを抜ける★★
	beq	a5, s6, 2f

	//★★s9を進めて、platform.hart_index2id[0], [1], [2], ...を順に調べる★★
	add	s9, s9, 4
	add	a4, a4, 1
	blt	a4, s7, 1b
	//★★s6 = hartindex
2:	add	s6, a4, zero
	//★★hartindexがhart数を超えているか?
	//★★  超える  : CPUが無効である、サブCPUを起動しない -> _start_hangへ
	//★★  超えない: CPUが有効である、サブCPUを起動する -> ブランチ命令の先へ
3:	bge	s6, s7, _start_hang

	//...

OpenSBIのロゴが出たあたりでブレークして各スレッドの実行している関数名を見ると、下記のようになります。

無効なCPU 2が_start_hang()で止まっている様子
(gdb) info thr
  Id   Target Id                    Frame
  1    Thread 1.1 (CPU#0 [halted ]) sbi_hsm_hart_wait (scratch=0x8008c000, hartid=0)
    at opensbi/lib/sbi/sbi_hsm.c:177
  2    Thread 1.2 (CPU#1 [running]) 0x0000000080020ffe in fdt32_to_cpu (x=50331648)
    at opensbi/lib/utils/libfdt/libfdt_env.h:57
* 3    Thread 1.3 (CPU#2 [halted ]) _start_hang ()
    at opensbi/firmware/fw_base.S:409
  4    Thread 1.4 (CPU#3 [halted ]) sbi_hsm_hart_wait (scratch=0x80088000, hartid=3)
    at opensbi/lib/sbi/sbi_hsm.c:177

Thread Id 3つまりCPU 2(※)だけ_start_hang()に居ることがわかりますね。

(※)GDBのThread Idは1スタートなのでThread Id 1, 2, 3, 4がCPU 0, 1, 2, 3に相当します。

編集者:すずき(2024/10/17 04:19)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link もっと前
2024年10月2日 >>> 2024年9月19日
link もっと後

管理用メニュー

link 記事を新規作成

<2024>
<<<10>>>
--12345
6789101112
13141516171819
20212223242526
2728293031--

最近のコメント5件

  • link 21年9月20日
    すずきさん (11/19 01:04)
    「It was my pleasure.」
  • link 21年9月20日
    whtさん (11/17 23:41)
    「This blog solves my ...」
  • link 24年10月1日
    すずきさん (10/06 03:41)
    「xrdpで十分動作しているので、Wayl...」
  • link 24年10月1日
    hdkさん (10/03 19:05)
    「GNOMEをお使いでしたら今はWayla...」
  • link 24年10月1日
    すずきさん (10/03 10:12)
    「私は逆にVNCサーバーに繋ぐ使い方をした...」

最近の記事3件

  • link 24年12月9日
    すずき (12/19 11:01)
    「[nvJPEGとNVJPGとJetson APIその4 - Jetson Linux API] 目次: Linux半年経ったら...」
  • link 24年12月11日
    すずき (12/18 00:00)
    「[nvJPEGとNVJPGとJetson APIその5 - Jetson Linux API JPEG decode編] 目次...」
  • link 24年12月13日
    すずき (12/18 00:00)
    「[nvJPEGとNVJPGとJetson APIその6 - Jetson Linux API JPEG encode編] 目次...」
link もっとみる

こんてんつ

open/close wiki
open/close Linux JM
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 2022年
open/close 2023年
open/close 2024年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDFファイル RSS 1.0

最終更新: 12/19 11:01