2013年2月27日 星期三

os2 warp 4.0



os2 warp 4.0 是大學時期購買的, 好像是 2800 NT (不確定), 已經超過十年了吧。在現今的硬體上, 可能無法執行了, 讓她復活在虛擬機器裡頭吧!使用 qemu 至少需要 1.0 之後的版本。

qemu-system-i386 -localtime -m 128 -hda os2.img -fda os2_warp_ex_0 -cdrom os2_warp40_ex.iso -boot order=a

qemu 1.0 抽換磁片的指令有點不同:

eject fda 改成 eject floppy0
change fda OS2W4-disk1.img 改成 change floppy0 OS2W4-disk1.img



感動阿!感動歸感動, 不過不會用, 現在我已經愛上 linux 了。
下面 3 個影片是 os2 warp 4.0 體驗版的安裝過程。







中文版的安裝磁片 3 壞了, 可以從光碟執行 cdinst.bat 重新製作。
下面這個影片是 os2 warp 4.0 中文正式版的安裝過程。



ref:

2013年2月25日 星期一

note

make a patch
diff -Naur old new > patch_file
patch -pN < patch_file 更新
patch -R -pN < patch_file 還原

Run X client in linux console
DISPLAY=:0.0 gnome-terminal

ubuntu compizconfig
sudo apt-get install compizconfig-settings-manager


vim replace
s/a>\r\(.*\)<\/span>/{\\bf \1}/

%s/\(.*\)<\/span>/\\section{\1}/gc

:s/\(.*\)<\/b>/{\\bf \1}/



vim 按下某 key, 產生某字串 by _13h:

1 :nmap<C-a> o\begin{verbatim}<esc>
2 :nmap<C-w> o\end{verbatim}<esc>
3 :imap <c-a> iaaa <esc>


Dropbox for Linux

網站雖然有 linux dropbox tool,
但是拜其 opensource 之賜, 在 debian 裡頭,
apt-get install dropbox
輕鬆搞定。

在 unix/linux 系統, 用指令找出硬碟裡的大檔案



du ' sort 以及 head 三個 三個常見的指令
du -cks * | sort -rn | head -11
alias hunter='du -cks * | sort -rn | head -11'


svn "gnome keyring" issue

http://old.nabble.com/disable-warning-about-gnome-keyring--td23506009.html

create config file
svn --config-dir /tmp/svn-config help

see the setting
password-stores = kwallet


模擬器:


ref: http://wei-hu-tw.blogspot.com/2007/11/embedded-linux.html
名稱    用途    官方網站
PearPC    模擬 PowerPC    http://pearpc.sourceforge.net
ARMphetamine    模擬 ARM(發展中止)    http://armphetamine.sourceforge.net/
Tarmac    模擬 ARM(發展中止)    http://davidsharp.com/tarmac/
SkyEye    模擬 ARM    http://www.skyeye.org/
ARMware    模擬 ARM    http://www.csie.ntu.edu.tw/~r88052/ARMware/tw/frame.html
表:常見的嵌入式平台模擬器



vsftpd.conf
anonymous 的設定, 可以 overwirte 檔案。

anon_umask=022
anon_other_write_enable=YES

windows shutdown
C:\WINDOWS\system32\at.exe 2:00 Shutdown -s

add svn version in source code


add $Rev$ to string.

svn propset svn:keywords "Rev" style.css


ref: http://dev.juokaz.com/php/automatic-svn-revision-number-in-source-code


在 maklefile 中使用 ifeq 和 or

$(filter ,)
名稱:過濾函數——filter。
功能:以模式過濾字符串中的單詞,保留符合模式的單詞。可以有多個模式。
返回:返回符合模式的字串。


ex:
if SELECT_A==y || SELECT_B==y
ifeq (y, $(filter $(SELECT_A) $(SELECT_B), y))



goto head file in vim

by ptt timTan


在 你的 header file 上按 gf 或是 ctrl w + f
vim 預設會在 .,/usr/include 這兩個地方找 檔案。
你的 project header 如果 是放在 /your/pwd/header/
請在你的 vimrc 上多做一件事 set path+=/your/pwd/header/

當然,cscope 也是不錯的好工具。


NFS root support linux kernel config

│ │ [*] Networking support --->

│ │ Networking options --->

│ │ [*] IP: kernel level autoconfiguration
│ │ [*] IP: DHCP support


│ │ File systems --->
│ │ [*] Network File Systems --->

│ │ <*> NFS client support
│ │ [*] Root file system on NFS

煮飯口訣

內鍋水量: 米 X 1.2
外鍋水量: 米 X 0.5

稀飯:
內鍋水量: 米 X 6
外鍋水量: 米 X 0.5

兩人份飯:
1.5 杯的米

兩人份粥:
0.8 ~ 1 杯的米


BBSFox 2.0.21

在 firefox 下玩 bbs:
https://addons.mozilla.org/en-us/firefox/addon/bbsfox/
安裝完畢之後, 在網址列打 telnet://ptt.cc 就會連到 ptt 了。

hot key : chrome://bbsfox/locale/help.htm

利用簡單的 Shell Script 抓你的 IP:

http://www.ylarge.com.tw/cms/article/27/220.html

# ifconfig eth0 | grep "inet addr" | tr -s ' ' ' ' | cut -d ' ' -f3 | cut -d ':' -f2

samba access symbolic link
ref: http://www.ubuntu-tw.org/modules/newbb/viewtopic.php?post_id=128058
edit smb.conf

follow symlinks = yes
unix extensions = no
wide links = yes


從 file command 得到 mime type


file -i a.tar

a.tar: application/x-tar; charset=binary


使用 smbclient copy smb server 檔案


ref: http://www.linuxso.com/command/smbclient.html
--user username%passwd, 此例子的密碼是空字串 ''


get <remote file name> [local file name]
           Copy the file called remote file name from the server to the
           machine running the client. If specified, name the local copy local
           file name. Note that all transfers in smbclient are binary. See
           also the lowercase command.


from samba server copy to local
$ smbclient -c "get e.iso /tmp/e.iso" \\\\127.0.0.1\\smb_test --user username%''



       put<local file name> [remote file name]
           Copy the file called local file name from the machine running the
           client to the server. If specified, name the remote copy remote
           file name. Note that all transfers in smbclient are binary. See
           also the lowercase command.

from local copy to samba server copy
$ /usr/bin/smbclient  -c "put /tmp/exam.d e.txt" //127.0.0.1/smb_test/ --user username%''

get timestamp in linux

date +%Y%m%d-%I%M%S

git archive


git archive --format=tar --prefix=code/ HEAD | gzip > /tmp/code.`date +%Y%m%d-%I%M%S`.tar.gz
git archive --format=tar --prefix=`basename $PWD`/ HEAD | gzip > /tmp/`basename $PWD`.`date +%Y%m%d-%I%M%S`.tar.gz

git log:
git log --graph --pretty=format:'%s - %Cred%h%Creset  %Cgreen(%cr)%Creset %an' --abbrev-commit --date=relative 

runpc! no 164 p: 162 探討 boost.tuple by 侯捷


sed 刪除某些行

sed -e '/^AAA$/,/^BBB$/d' afile


mprotect

man mprotect
mprotect - set protection on a region of memory
ref: http://blog.linux.org.tw/~jserv/archives/2012/05/_python_shellco.html


mount samba filesystem in linux

# mkdir /mnt/cifs
# mount -t cifs //server-name/share-name /mnt/cifs -o username=shareuser,password=sharepassword,domain=nixcraft
# mount -t cifs //192.168.101.100/sales /mnt/cifs -o username=shareuser,password=sharepassword,domain=nixcraft
ref: http://www.cyberciti.biz/faq/linux-mount-cifs-windows-share/

xvidcap

linux 桌面錄影軟體 

run gnome-terminal as root

gnome-terminal -x bash -c "sudo bash"


vim 指令

慢慢來, 一次太多也記不住。

gd "將游標所在字串視為 local 變數,找到定義此 local 變數的地方 (如果有的話)
[[ "找函數的開頭
]] "找下一個函數的開頭

gcc version and macor

gcc -E -dM - < /dev/null |less ref: http://stackoverflow.com/questions/1936719/what-are-the-gcc-preprocessor-flags-for-the-compilers-version-number

車險王

http://www.icartalex.com.tw/

可以查看哪家的強制險有贈品。

linux set timezone

http://yen.chic.tw/2009/05/linux-time-zone.html

設定 Linux Time Zone   


#ls -F /usr/share/zoneinfo/   
#ln -sf /usr/share/zoneinfo/Asia/Taipei /etc/localtime


將 vmware image 轉成 qemu image


qemu-img convert vmwareVM.vmdk -O qcow2 qemuVM.img
ref: http://www.ehow.com/how_7153252_mount-vmware-image-qemu.html


 zip 目前目錄的檔案 (包含子目錄) 成 foo.zip
 zip -r foo . -i "/*"

組合語言 gas at&t syntax rep 語法:
8048196:       f3 a4                   rep movsb %ds:(%esi),%es:(%edi)


mount 軟碟很簡單, mount -o loop diska.img /mnt
硬碟複雜點:
計算 partition offset, 使用 fdisk, 切換到 sector (type u command) 查看開始 sector。以這例子來說是 63。
63*512 = 32256

losetup -o 32256 /dev/loop1 ./dos.img
mount /dev/loop1 /mnt/

linux 連到 windows 遠端桌面
rdesktop -u user_name  -p password -f 1.2.3.4 -g 640X480
ref: http://isong.blogspot.tw/2013/01/windows-8-linux-client.html


vcd convert to avi
ref: http://www.askmeaboutlinux.com/?p=909
   
Convert VCD to AVI using mencoder
By Geetu R. Vaswani, on July 4th, 2010

$ mplayer vcd://2 to check the track that needs to be converted.
$ mencoder vcd://2 -o file.avi -oac copy -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=2000
Converts the VCD track to AVI file.

Start Conversion:
#mencoder vcd://2 -o movie.avi -oac copy -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=2000

寫了兩個簡單的 script 來用。

batch.sh 3
會產生 3-1.avi ~ 3-9.avi

batch.sh 5
會產生 5-1.avi ~ 5-9.avi

vcd2avi.sh
#!/bin/sh
if [ "$1" = "" -o "$2" = "" ] ; then
  echo $0 track_no disk_no
  echo "ex: $0 3 1"
  exit -1
fi
cmd="mencoder vcd://$1 -o $2-$1.avi -oac copy -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=2000"
echo "run cmd: $cmd"
sleep 1
$cmd

batch.sh
#!/bin/sh
if [ "$1" = "" ] ; then
  echo $0 disk_no
  exit -1
fi

i=1
cmd=""
while [ $i -le 9 ] ;do
cmd="./vcd2avi.sh $i $1"
echo "$cmd"
$cmd
i=`expr $i + 1`
done


let qemu use alsa
export QEMU_AUDIO_DRV=alsa


rsync

ref: http://linux.vbird.org/linux_server/0310telnetssh.php#rsync
/home/descent/a-dir need create first
rsync -av -e ssh a-dir/ descent@p.ban.org:/home/descent/a-dir/
rsync -av -e ssh user@rsh.server:/etc /tmp

如何使用GCC產生C/Assembly Interleavd Output

提問於cszone, LCamel透過google在djgpp的網站找到解法:
gcc -c -g -Wa,-a,-ad test.c

這個方法相當巧妙, 原理是利用 -g 產生 C source level debug symbols,
再透過 -Wa 把 -a -ad 傳給 gnu assembler, 其中:
-a requests high-level, assembly, and symbols listing.
-ad omits debugging directives from the listing.

亦可搭配-O2或-O3使用, 觀察optimized的code.

http://www.delorie.com/djgpp//mail-archives/browse.cgi?p=djgpp/2000/02/29/14:19:57


what is .rel.eh_frame REL in elf section

http://forum.osdev.org/viewtopic.php?f=1&t=26832&p=224535#p224535
search System V ABI documents:
https://www.google.com.tw/search?q=System+V+ABI+documents&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:en-US:official&client=firefox-a&channel=fflb

黑蘋果


VirtualBox 安裝 Mac OS X 86 + EFI 安裝到硬碟 MBR 問題解決

virtualbox 可以直接讀取 dmg, 不用轉 iso, 我的測試可以順利安裝完成, 不用強迫重開機。

如何降低膽固醇
醫生說: 一個禮拜需運動 5 天, 30 分鐘以上, 心跳數達 130, 膽固醇只能靠運動降下來, 無法靠飲食控制調降。


ubuntu  12.04 改成自己想要的桌面環境
亂試的結果, 不保證可用。
apt-get install gdm icewm
使用 gdm login 時選 icewm, 這樣就不會看到 unity。

icewm 重抓設定

killall -HUP icewm


安裝 linux module 到其他目錄
make modules_install  INSTALL_MOD_PATH=/tmp/aa



遇到麻煩的 bug
要出動 gdb with core dump

c2d_err
root@WEI-YA ~$ cd /home/weiya/mmadplayer
root@WEI-YA /home/weiya/mmadplayer$ gdb -c core  mmadplayer
GNU gdb 6.6
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "arm-none-linux-gnueabi"...
Using host libthread_db library "/lib/libthread_db.so.1".

warning: exec file is newer than core file.
Core was generated by `./mmadplayer'.
Program terminated with signal 11, Segmentation fault.
#0  0x00013430 in QString (this=0x41a004b8, other=@0xffffffe4)
    at ../../Software/Build/ltib/rootfs/usr/local/Trolltech/qt4/include/QtCore/qstring.h:725
725     ../../Software/Build/ltib/rootfs/usr/local/Trolltech/qt4/include/QtCore/qstring.h: No such file or directory.
        in ../../Software/Build/ltib/rootfs/usr/local/Trolltech/qt4/include/QtCore/qstring.h
(gdb) bt
#0  0x00013430 in QString (this=0x41a004b8, other=@0xffffffe4)
    at ../../Software/Build/ltib/rootfs/usr/local/Trolltech/qt4/include/QtCore/qstring.h:725
#1  0x000177d4 in QMutexLocker (this=0x0, m=0x0)
    at ../../Software/Build/ltib/rootfs/usr/local/Trolltech/qt4/include/QtCore/qmutex.h:110
#2  0x00017a7c in LogMessage::insert_log (this=0x0, text=@0x0) at ../mmadplayer/tool.h:62
#3  0x000175d8 in operator+ (s1=0x41a00468 "�\004�A�\004�A", s2=@0x0)
    at ../../Software/Build/ltib/rootfs/usr/local/Trolltech/qt4/include/QtCore/qstring.h:1031
#4  0x0001744c in __static_initialization_and_destruction_0 (__initialize_p=1058289516, __priority=2122316944)
    at ../mmadplayer/c2d.cpp:135
#5  0x00015a98 in PlayTicker::play (this=0x3f14376c, pl_data=0x41a00468) at ../mmadplayer/c2d.cpp:23
#6  0x00042518 in i2c_smbus_read_byte_data (file=736823300, command=63 '?') at ../mmadplayer/i2c.cpp:173
#7  0x2bebc834 in ?? ()
Backtrace stopped: frame did not save the PC


刪除在 ntfs 上的超長檔名目錄

steam 建立了超長檔名目錄的備份:
Tomb Raider Legend and Tomb Raider Anniversary and Tomb Raider Underworld and
Alice Madness Returns and Lara Croft and the Guardian of Light and Tomb
Raider and Tomb Raider I and Tomb Raider The Last Revelation and Tomb Raider
Chronicles and Tomb Raider (

但是 windows8 無法刪除/進入/改名這個目錄,

http://support.microsoft.com/kb/320081

這篇寫的都沒用。

最後 mount 在 ubuntu 下刪除這個目錄。

在 ubuntu 環境下, 可以正常刪除/進入/改名 這個目錄。

git - push to remote repository

cd /path/to/my/repo
git remote add origin ssh://git@bitbucket.org/dsung/abc.git
git push -u origin --all # pushes up the repo and its refs for the first time
git push -u origin --tags # pushes up any tags

小強餅乾
硼酸、麵粉、糖或在一起不用烤焙, 小強吃了之後會慢慢才死掉。

2013年2月21日 星期四

x86 call/ret 會 push/pop 2byte or 4 byte in stack??

最近踩到這個地雷, 這是在我要將 kernel loader 改為使用 big real mode 以便載入超過 1M 的 kernel 時遇到的。在 x86 16bit 環境下使用 gas, gcc 產生的程式碼有點小差異。

16 111: e8 44 00 call 158 <init_bss_asm>

L16 這是 gas 組語產生的 machine code。

69 1ac: 66 e8 65 ff ff ff calll 117 <asm_4g_memcpy>

L69 這是 gcc c 語言產生的 machine code。多了一個 66 prefix, 改變 operand size 大小。在 16 bit 模式下, operand size 會改變成 32bit, 本來使用 call 指令後 (in 16 bit mode), %esp 是 -2, 但是加了這個 0x66 prefix %esp 會 -4, 所以要用 retl 才會讓 %esp +4 回來。L54, L71 的 ret 指令就差了一個 0x66 也是類似的道理。

結果是這樣的:
呼叫 init_bss_asm 前後, %esp 會加減 2; 呼叫 asm_4g_memcpy, %esp 卻會加減 4。
asm_4g_memcpy 是組語 function, 我在 c code 呼叫 asm_4g_memcpy, %esp 會減 4。而原本 asm_4g_memcpy 結尾寫 ret, 離開 asm_4g_memcpy 返回原 function 後, %esp 會加 2,  要寫成 retl 才會加 4。原本我是寫 ret, 結果造成 stack 在呼叫 asm_4g_memcpy 之後會出問題。

這問題花了我兩個下午才找到, 還得靠著 bochs 才能發現。除非直些看 machine code, 否則很難發現這問題。因為:

gcc -DIPC -std=c99 -fno-stack-protector -m32 -ffreestanding -fno-builtin -g -Iinclude -I../include  -S kernel_loader.c

從 kernel_loader.s 只能看到 call asm_4g_memcpy, 而不是 calll asm_4g_memcpy, 看不到 66 這個 prefix。

call 和 calll 會翻成不同的 machine code (16bit mode):
call -> e8 XX
calll -> 66 e8 XX

objdump -m i8086 -d kloaderp.bin.elf
1
2 kloaderp.bin.elf: file format elf32-i386
3
4
5 Disassembly of section .text:
6
7 00000100 <_start>:
8 100: 87 db xchg %bx,%bx
9 102: 8c c8 mov %cs,%ax
10 104: 8e d8 mov %ax,%ds
11 106: 8e c0 mov %ax,%es
12 108: 8e e0 mov %ax,%fs
13 10a: 8e e8 mov %ax,%gs
14 10c: 8e d0 mov %ax,%ss
15 10e: bc f0 ff mov $0xfff0,%sp
16 111: e8 44 00 call 158 <init_bss_asm>
17 114: e8 5d 00 call 174 <start_c>
18
19 00000117 <asm_4g_memcpy>:
20 117: 66 55 push %ebp
21 119: 66 89 e5 mov %esp,%ebp
22 11c: 66 56 push %esi
23 11e: 66 57 push %edi
24 120: 66 51 push %ecx
25 122: 67 66 8b 7d 08 mov 0x8(%ebp),%edi
26 127: 67 66 8b 75 0c mov 0xc(%ebp),%esi
27 12c: 67 66 8b 4d 10 mov 0x10(%ebp),%ecx
28 131: 66 83 f9 00 cmp $0x0,%ecx
29 135: 74 0f je 146 <asm_4g_memcpy+0x2f>
30 137: 67 8a 06 mov (%esi),%al
31 13a: 66 46 inc %esi
32 13c: 64 67 88 07 mov %al,%fs:(%edi)
33 140: 66 47 inc %edi
34 142: 66 49 dec %ecx
35 144: eb eb jmp 131 <asm_4g_memcpy+0x1a>
36 146: 67 66 8b 45 08 mov 0x8(%ebp),%eax
37 14b: 66 59 pop %ecx
38 14d: 66 5f pop %edi
39 14f: 66 5e pop %esi
40 151: 66 89 ec mov %ebp,%esp
41 154: 66 5d pop %ebp
42 156: 66 c3 retl
43
44 00000158 <init_bss_asm>:
45 158: bf c0 05 mov $0x5c0,%di
46 15b: be c0 05 mov $0x5c0,%si
47 15e: eb 0f jmp 16f <init_bss_asm+0x17>
48 160: 66 b8 00 00 00 00 mov $0x0,%eax
49 166: 89 f0 mov %si,%ax
50 168: 67 c6 00 01 movb $0x1,(%eax)
51 16c: 83 c6 01 add $0x1,%si
52 16f: 39 fe cmp %di,%si
53 171: 75 ed jne 160 <init_bss_asm+0x8>
54 173: c3 ret
55
56 00000174 <start_c>:
57 174: 66 55 push %ebp
58 176: 66 89 e5 mov %esp,%ebp
59 179: 66 83 ec 28 sub $0x28,%esp
60 17d: 67 c7 45 f6 00 00 movw $0x0,-0xa(%ebp)
61 183: 67 66 c7 45 f0 64 00 movl $0x64,-0x10(%ebp)
62 18a: 00 00
63 18c: 67 66 0f b7 45 f6 movzwl -0xa(%ebp),%eax
64 192: 67 66 c7 44 24 08 00 movl $0x200,0x8(%esp)
65 199: 02 00 00
66 19c: 67 66 89 44 24 04 mov %eax,0x4(%esp)
67 1a2: 67 66 8b 45 f0 mov -0x10(%ebp),%eax
68 1a7: 67 66 89 04 24 mov %eax,(%esp)
69 1ac: 66 e8 65 ff ff ff calll 117 <asm_4g_memcpy>
70 1b2: 66 c9 leavel
71 1b4: 66 c3 retl

測試 source code:

kloader_init.S
1 /*
2 * the kernel loader will initialize c runtime and enter x86 protected mode
3 */
4
5
6 #define BIG_REAL_MODE
7
8 .data
9
10 LABEL_STACK:
11 .space 1024, 0
12 .set top_of_stack, (. - LABEL_STACK)
13
14
15
16 .code16
17 .extern __bss_start__
18 .extern __bss_end__
19
20 .text
21 .global _start
22 _start:
23 xchg %bx, %bx
24 mov %cs, %ax
25 #mov $0xa00, %ax
26 mov %ax, %ds
27 mov %ax, %es
28 mov %ax, %fs
29 mov %ax, %gs
30
31 mov %ax, %ss
32 # setup stack
33 mov $0xfff0, %sp # why not setting 0xffff to %sp, in ms dos, 0xfff0 is ok, 0xffb will get core dump
34
35 call init_bss_asm
36 call start_c

71
72 # use big real mode copy to 4g range
73 # use %fs for segment register, %fs points to 4g memory space
74 .globl asm_4g_memcpy
75 # ex:
76 # asm_absolute_memcpy((u8*)0x100, (u8 *)IMAGE_LMA, 512*3);
77 # copy IMAGE_LMA to 0x100
78 asm_4g_memcpy:
79 pushl %ebp
80 mov %esp, %ebp
81
82 pushl %esi
83 pushl %edi
84 pushl %ecx
85
86 mov 8(%ebp), %edi /* Destination */
87 mov 12(%ebp), %esi /* Source */
88 mov 16(%ebp), %ecx /* Counter */
89 1:
90 cmp $0, %ecx /* Loop counter */
91 jz 2f
92 movb %ds:(%esi), %al
93 inc %esi
94 movb %al, %fs:(%edi)
95 inc %edi
96 dec %ecx
97 jmp 1b
98 2:
99 mov 8(%ebp), %eax
100 pop %ecx
101 pop %edi
102 pop %esi
103 mov %ebp, %esp
104 pop %ebp
105 retl
106
107 # init bss
108 init_bss_asm:
109 movw $__bss_end__, %di /* Destination */
110 movw $__bss_start__, %si /* Source */
111 # movw $0x0, %ax
112 # movw %ax, %gs
113 jmp 2f
114 1:
115 mov $0, %eax
116 movw %si, %ax
117 movb $0x1, (%eax)
118 # movb $0x1, %ds:(%eax)
119 add $1, %si
120
121 2:
122 cmpw %di, %si
123 jne 1b
124 ret

kernel_loader.c
1 __asm__(".code16gcc\n");
2
3 typedef signed char s8;
4 typedef signed short s16;
5 typedef signed int s32;
6
7 typedef unsigned char u8;
8 typedef unsigned short u16;
9 typedef unsigned int u32;
10
11 typedef unsigned long long u64;
12
13
14 void asm_4g_memcpy(u32 dest, u32 src, int n);
15 void start_c()
16 {
17 u16 buff=0;
18 u32 kernel_addr=100;
19 asm_4g_memcpy(kernel_addr, (u16)buff, 512);
20 }

完整範例:
https://github.com/descent/progs/tree/master/gas_gcc_16bit

很開心的以為搞定, 結果遇上另外的難題

而若是在組合語言 call c function, 要用 calll c_func, 不能用 call c_func, 免得 %esp 又差了 2。

ref: x86/x64 指令编码内幕(适用于 AMD/Intel)

2013年2月17日 星期日

在 x86 真實模式載入大於 1M 的 kernel

懷念完美少女遊戲後, 該來點枯燥乏味的東西, 趕在 2013 春節最後一天完成 (20130217), 真是開心。這問題還真有點困難, 因為在 x86 真實模式下, 只能存取 1M 記憶體位址, 但實際上比 1M 還少, 還記得 dos 的 640K 限制嗎?扣掉 bios/介面卡所使用的記憶體空間, 大概只有 0x0000:0x0500 ~ 0x9000:0xFFFF 這範圍的記憶體可用。
大約是: 0xa0000 - 0x500 = 654080 byte 。

參考這張記憶體配置圖: http://descent-incoming.blogspot.tw/2012/11/elf.html

simple os kernel + romfs ramdisk 就必須小於 654080 byte。

kernel 要超過很不容易, 但是 ramdisk 隨便塞個檔案就容易超過了, 所以該是來解決這問題了。
有兩個方法:
  1. 自己處理磁碟載入的程式碼, 也就是自己刻 floppy disk, ide/sata driver, 不使用 bios 0x13 call, 這樣就可以在保護模式下驅動磁碟機。
  2. 使用 big real mode。

柿子挑軟的吃, 方案一實在太困難, usb floppy 要搞定的東西可不少, 不像以前使用單純的軟碟介面, 光是處理 usb 可就不輕鬆。我決定使用 big real mode。

big real mode 也稱為 unreal mode, flat real mode 簡單說就是在 real mode 下, 但是可以存取 4g 的記憶體空間, 怎麼做到?大概是這樣:
切入保護模式, 設定存取 4g 的 gdt/selector, 設定這個 selector 到某個 segment register (ex: %fs), 切回真實模式, 使用 %fs 來定址。

big real mode:

big real mode 可以調用呼叫真實模式下的 bios call, 所以我就可以使用 int 0x13 來讀取磁碟上的檔案, 每次讀取一個 sector, 然後複製到 1MB 以外的位址 (我是複製到 0x300000), 這樣就可以在真實模式下載入一個超過 1MB 的 kernel。

我使用 %fs:0x300000 這樣的方式將 kernel 複製到這個位址 (in big real mode)。%fs 是 0x28 (base = 0, limit = 4G), 在我的認知, 我認為絕對位址應該是 0x300000, 也就是我複製 kernel 到物理位址 0x300000。而切換到保護模式後 (同一份 gdt), 讀取 0x300000 也應該可以讀到 kernel。

一開始我在 qemu/bochs 測試, 如我所願, 我也使用 bochs 內建 debugger 觀看 0x300000 的位址, 的確是 kernel 的內容。

本來以為已經搞定, 模擬器 qemu/bochs 都沒問題, 開心的不得了, 在真實機器測試應該也可順利通過, but ... 在真實機器下卻不是這樣, 程式完全不正常, 沒什麼比這還令人沮喪了。無法在真實機器執行, 這程式就沒意義了, 對我來說, 這就是錯誤的程式, 我不希望這程式只能活在虛擬機環境。

真實機器可沒有那麼好的 debug 環境, 透過冥想 + debug code, 勉強在真實機器上完成了。

在真實機器上, %fs:0x300000 並不是存取到 0x300000, 而是 0x300000+0x28x16。我如何得知?因為我寫程式去 dump 0x300000 的內容, 並不是我預期的 kernel, 而 0x300000+0x28x16 才是 kernel 的內容。我猜測在真實機器上 %fs:0x300000 存取的不是 0x300000 而是 0x300000+0x28x16, 因為 %fs 是 0x28 的關係。

我疑惑的是 qemu/bochs 的結果和真實機器不同, 是我搞錯什麼了? 在 eeepc 901 和 amd 的機器上測試, %fs:0x300000 都是得到 0x300000+0x28x16, 而不是我預期的 0x300000。

其實我有用 %fs:0xb8000 來顯示 char (in big real mode), 並不是在第0行, 第0列的位址, 才讓我想到有可能差了 0x28X16。下圖的藍色字串便是使用 %fs:0xb8000 來印到螢幕。

寄件者 write_os
在 eeepc 901 上測試, 這個 kernel size: 672596 超過 654080, 證明突破 640K 真實模式下的限制。



上圖是 simple os 執行畫面, 那麼問題出在哪裡呢?

selector 0x28 in %fs, 這是我在 big real mode 設定的 gdt/selector。

LABEL_DESC_4G_RW: Descriptor  0, 0xfffff, DA_DRW | DA_32 | DA_LIMIT_4K

0x28 這個 selector 定義的 segment 如上:
base:0
limit: 0xffffffff

整個 4G 空間。

在 qemu/bochs 保護模式下, 使用 %fs:0x300000 時, 是指到絕對位址 0x300000, 3M 的位址上。但在我的 eeepc 901 真實機器上則是 0x300000 + 0x28*16 = 0x300280

#ifdef REAL_PC
  u32 buff = LOAD_KERNEL_ADDR + (0x28*16);
#else
  u32 buff = LOAD_KERNEL_ADDR;
#endif

所以我的程式多了這個 REAL_PC macro。

下面的圖是另外一台 nb, amd 的 cpu, 也可正常開到 simple os 畫面, 讓我對程式的正確性信心大增。



前面說勉強可用是因為若插入 debug function, insert p_dump_u8(buff, 32); in copy_elf_code(), kernel 還是無法正常載入, dump_u8() 是 debug function, 所以又得靠冥想來解決這問題了。

好累, 沒處理掉這問題, 休假期間都睡不安穩阿!

附上一起和我 debug 的 ibm usb floppy disk, 辛苦啦, 喀喀喀的讀取聲, 緩慢的讀取速度, 還真懷念。

寄件者 write_os

使用 usb storage 測試 1M 的 kernel (1314148 bytes), 也能順利載入。也許你會有個疑問, 為什麼不用軟碟測試?
  1. 軟碟要讀很久, 我等著等著會睡著, 要是失敗了, 很浪費時間。
  2. 軟碟機資料很容易出錯, 有錯的話, 我不知道是程式錯了還是軟碟片本身資料就是錯的。



到這裡都還在真實模式下 (正確來說是 big real mode), 按下空白鍵後就會切到保護模式, 再來便會跳到 kernel 的 code, 執行 kernel。

usb storage 的速度比軟碟片快多了, 畫面的 '.' 代表讀入一個 sector (512 byte), 所以 kernel 檔案愈大看到的 '.' 就愈多, 看著畫面上滿滿的 '.' 還蠻有成就感的。



https://github.com/descent/simple_os
git commit: 1ebf4fc42c484e0d2d2d0e9027ec4e9654ccb341

ref: x86/x64体系探索及编程 by 邓志

2013年2月15日 星期五

龍騎士 III

寄件者 龍騎士 3

定價 900 NT, 在我的高中時代算是很貴的遊戲。我買這塊遊戲的時候還沒有買光碟機, 不過我並不想購買磁片版本, 想也知道我早晚會購入光碟機, 何必急於一時, 只是真的是蠻久之後的事情了。所以那時候先借給有光碟機 (兩倍速光碟機) 的高中同學玩, 我則是在旁觀看畫面。

我在 linux 使用 dosbox 重現遊戲畫面。
http://www.dosbox.com/wiki/Basic_Setup_and_Installation_of_DosBox

in linux:
mount -o dragon3.iso /mnt

in dosbox:
Z:\>MOUNT E /mnt -t cdrom
mount c /host
c:
cd \GAMES\XENTAR
kx

http://www.dosbox.com/wiki/Special_Keys

ctrl+f10 release mouse



美國配音真的很搞笑, 低級的無料笑點, 和台灣的善良風情格格不入。遊戲畫面在當時算是很精緻, 不過美式風格的翻譯真的是很奇怪。

T-shirt是另外購買的, 忘記多少錢了 (看型錄是 400 NT), 還有幾件也想買, 那時沒買有點後悔。海報則是遊戲自帶內附的, 這種美少女遊戲似乎都會附上和封面一樣的海報,這張海報很漂亮, 也很大張, 我還蠻喜歡的。



在當時也是少數的光碟 pc game, 我直到很久之後才能玩這塊遊戲, 雖然不能花錢升級才能 XX, 嘿嘿 ... 你知道的, but ...

ref: http://webbbs.gamer.com.tw/gemread.php?brd=H-Game&f=F0R3PCDN&n=3

作 者:sholy (嗯~~隨便叫啦)
標 題:Re: 龍騎士3....
時 間:バハムート (Tue Jul 15 11:29:17 1997)

※ 引述《lulala (魯拉拉)》之銘言:
 : ※ 引述《Firebird (火鳥)》之銘言:
: :    微波軟體有在雜誌上聲明,本遊戲沒有升級版!
: :    要看原版的圖圖,找片圖檔光碟來看吧.
:      絕對有 以前我就會用 是用pctools改kx.exe參數忘了....
 就這樣囉

龍騎士III中英文光碟版

───────────

<改成完整版>



FILE:FX.EXE KX.EXE

SEARCH 80 3E CB 0E 00 74 13

CHANGE C6 06 CB 0E 01 90 90

show me the body




這麼貴的遊戲, 手冊竟然是黑白的,比美少女夢工廠2 還沒誠意, 遊戲手冊可是蒐藏的重點。包裝盒上的雙語不知道是什麼意思? 我一直以為是有日文或是美語語音, 不過感覺好像是英文/中文這樣的意思。




龍騎士3(攻略): http://blog.xuite.net/laurated/game/45163059-%E9%BE%8D%E9%A8%8E%E5%A3%AB3%28%E6%94%BB%E7%95%A5%29

ref:
http://www.gamebase.com.tw/forum/30032/topic/95472616/1 

2013年2月10日 星期日

懷舊老遊戲 - 機甲之夢

the 1st edition: 20130210 (7)
the 2nd edition: 20130210 (7)
微波出版的機甲之夢, 我有印象的微波美少女遊戲有龍騎士3、機甲之夢、眼鏡蛇任務。機甲之夢 560 元定價在當時可不算便宜, 對於還是學生的我來說可是一大負擔。

寄件者 格鬥美少女 遊戲/雜誌

以下畫面是 pc9801 的人行使い, 這是格鬥遊戲, 然後打輸的人不知道為什麼會被莫名的脫衣服, 不過這就是遊戲的重點。



10 片 5.25 吋磁片, 在當時可算是容量大的遊戲, 光是安裝就要花不少時間, 磁碟機的龜速可是慢的嚇人。

不知道從什麼時候開始, 台灣電腦遊戲市場開始湧入大量的美少女遊戲, 當時的資訊很有限, 但大多玩家也都知道可以藉由 dos/V 來玩日本的美少女遊戲, 不過有些遊戲廠商已經嗅到這股商機, 推出一些中文化的版本。

機甲之夢是人行使い的英文版本中文化而來, 對比 pc9801 的版本, 加了一點人物對話模式, 要在主畫面和其他人物談話, 之後才能進入戰鬥畫面, 而 pc9801 版本就很乾脆, 直接對戰脫衣。

美少女遊戲大多是冒險類型的遊戲, 很少看到格鬥類型的。用鍵盤玩格鬥遊戲不是很方便, 尤其是一些絕招, 要靠著複雜的按鍵來組合起來, 不是發不出來就是手指頭快要打結。

我那時候喜歡用一隻可以瞬間移動的角色 - 銀龍, 可以很容易就打敗電腦。

記得當時的軟體世界這本遊戲雜誌還有一個專欄是在討論這樣的 18 禁遊戲, 當時可是很受歡迎的專欄, 文字很多, 但我相信更多人都是看圖。

從這時期開始, 除了蒐集這些美少女遊戲外, 我還會去找遊戲畫冊, 當然都是日文版本, 售價可不便宜。fig 6, 7 便是相關的日文雜誌, 這本是介紹美少女格鬥相關遊戲, 裡頭提到三款遊戲, 只有一款台灣沒進, 另外一款是摔角遊戲 - 天使角力賽, 我也有購得, 不過在台灣似乎不是很有名。



fig 6. 日文遊戲雜誌 fig 7. 日文遊戲雜誌內頁

這是屬於 18 禁遊戲, 遊戲要升級的話要滿 18 歲, 並另付工本費 100 元, 這樣才有養眼的畫面,又多撈 100 元, 當然我沒有花 100 元去升級, 真奇怪,不像我。

很抱歉沒有遊戲畫面, 我實在不知道怎麼讀取 5.25 寸磁片, 看來只能當作永遠的古董了。

感謝 ptt EDGE, 以下是機甲之夢片頭畫面 (英文版本, 這個影片錄的不完美, 改放另外一個影片):

20230904 之後, 我把 metal lace CD 版本 (下載) 跑了起來, cd 版本多了語音, 並且也在 steam deck 上執行, 在掌機執行玩起來方便許多。



pc9801 版本和英文移植版的比起來, 音樂單調很多, 不知道是不是有重製音樂的部份。

2013年2月7日 星期四

執行位址 0 的程式碼

ptr.c
 1 int main(int argc, const char *argv[])
 2 {
 3 #if 1
 4   unsigned int addr = 0;
 5   goto *addr; 
5.5  // goto *(0); 
 6 #else
 7   (*(void(*)())0)();
 8 #endif
 9   return 0;
10 }

在 C 陷阱與缺陷 (C Traps and Pitfalls) 上看到的, 令人害怕的語法。 使用 goto 就清楚多了吧!

有興趣的朋友可以更進一步看看反組譯後的組合語言, 很有趣哦!

不過使用 goto 和 function 語意是不同的:


b.c
1 int main(int argc, const char *argv[])
2 {
3   (*(void(*)())(0x22))();
4   goto *(0x20); 
5   return 0;
6 }

objdump -d a.out
 1 08048404 <main>:
 2  8048404:       55                      push   %ebp
 3  8048405:       89 e5                   mov    %esp,%ebp
 4  8048407:       83 e4 f0                and    $0xfffffff0,%esp
 5  804840a:       b8 22 00 00 00          mov    $0x22,%eax
 6  804840f:       ff d0                   call   *%eax
 7  8048411:       b8 20 00 00 00          mov    $0x20,%eax
 8  8048416:       ff e0                   jmp    *%eax
 9  8048418:       90                      nop
10  8048419:       8d b4 26 00 00 00 00    lea    0x0(%esi,%eiz,1),%esi

我實在太大意了。
call, jmp is different.

至於那個 %eiz 是什呢?
ref:
http://blog.csdn.net/unbutun/article/details/6661275

2013年2月5日 星期二

c 語言的 char 是 signed 還是 unsigned

作者: dryman (dryman) 看板: Programming
標題: Re: [請益] C 變數型態 可攜
時間: Mon Feb 4 11:02:52 2013

http://www.ptt.cc/bbs/Programming/M.1359946975.A.AFC.html

這篇提到一個有趣的程式碼:

a.c
 1 #include <stdio.h>
 2 
 3 int main(void)
 4 {
 5   unsigned char a = 0xff;
 6   char b = 0xff;
 7   int c = a==b; // true, or false?
 8   printf("C: %d\n",c);
 9   printf("a: %d\n", a);
10   printf("b: %d\n", b);
11   return 0;
12 }

不過 「char 是 signed 或是 unsigned 是由 c compiler 決定的」, 並不是標準, 在 gcc 上得到 0, 那麼在其他的 c compiler 的結果呢? 找到反證才能證明, 才能確信上面的話是對的。

我總是對這樣的事情半信半疑, 雖然書上應該不會有錯, 但總是希望找到證明。還好, 很容易就找到了。

openwatcom c/c++ 就是一個反例:

C: 1
a: 255
b: 255
這是由 openwatcom c/c++ 編譯後的執行結果, char b 是 unsigned。

gnu c 的版本呢?
C: 0
a: 255
b: -1
char b 是 signed。

使用 char 要記得這件事, 要不然遇到 signed/unsiged 地雷,  可是想破頭都不知道為什麼。
這是在 C 專家編程這本書看到的。

2013年2月3日 星期日

kernel loader issue in bochs

issue: 使用 bochs 2.6, kernel loader 無法載入 kernel

使用自動變數
u16 offset, next_cluster, cur_cluster;
在 bochs 2.6 下 kernel loader 無法載入 kernel

使用 static 變數 + gcc 4.4
static u16 offset, next_cluster, cur_cluster;
就沒問題 ,但若使用 gcc 4.7 compile, 還是一樣的問題。
很值得看看, 應該是 stack 這邊出了狀況, 看起來又不太像, 慘 ...

每一次的問題都是一次很好的學習機會。

git@github.com:descent/simple_os.git

issue:
git commit: c7229045fd1fb93edff72f2e816eedce6c408c30

fixed only under gcc 4.4
git commit: 7138421dd7c683734cdf774322821b943cc09b78


fixed under gcc 4.7

把 volatile u8 *buff 改成 u16 buff, 讓 "b"(buff)

31 __asm__ __volatile__ 
32 (
33 @@ -349,6 +354,10 @@ int __REGPARM read_sector(volatile u8 *buff, u8 sector_no, u8 track_no, u8 head_
34  :"a"(0x0200|blocks), "b"(buff), "c"(track_no << 8 | sector_no), "d"(head_no << 8 | disk_no)
35 ); 

直接吃 u16 的值, 可以修復這問題, 可是還沒找到 root cause。

git diff f78742eea8d145fcbb8b302bd1f7491d16d783b8 ff8d23e70841af5cc48b7131aca6a04d5e2233ce
 1 diff --git a/kernel_loader/kernel_loader.c b/kernel_loader/kernel_loader.c
 2 index 3a071ca..464da43 100644
 3 --- a/kernel_loader/kernel_loader.c
 4 +++ b/kernel_loader/kernel_loader.c
 5 @@ -314,7 +314,7 @@ int __REGPARM __NOINLINE get_drive_params(drive_params_t    *p, unsigned char
 6  // not 0: fail
 7  // if using the function read floppy fail, suggest reset floppy disk,
 8  // than try twice again.
 9 -int __REGPARM read_sector(volatile u8 *buff, u8 sector_no, u8 track_no, u8 head_no, u8 disk_no, u8 blocks)
10 +int __REGPARM read_sector(u16 buff, u8 sector_no, u8 track_no, u8 head_no, u8 disk_no, u8 blocks)
11  {
12    //bios_wait_key();
13  #if 0
14 @@ -333,12 +333,17 @@ int __REGPARM read_sector(volatile u8 *buff, u8 sector_no, u8 track_no, u8 head_
15  //  __asm__ __volatile__("movb $2, %ah\n"); 
16  //  __asm__ __volatile__("movb $1, %al\n"); 
17  #if 1
18 -    //BOCHS_MB
19    // read sector to %es:%bx, if %bx is more than 64k, need change %es
20    // to next 64k beginning address
21    // ref: http://dc0d32.blogspot.tw/2010/06/real-mode-in-c-with-gcc-writing.html
22    u16 num_blocks_transferred = 0;
23    u8 failed = 0;
24 +  //BOCHS_MB
25 +  //__asm__ __volatile__("xchg %bx, %bx");
26 +  __asm__ __volatile__("push %ax");
27 +  __asm__ __volatile__("push %bx");
28 +  __asm__ __volatile__("push %cx");
29 +  __asm__ __volatile__("push %dx");
30  
31    __asm__ __volatile__ 
32      (
33 @@ -349,6 +354,10 @@ int __REGPARM read_sector(volatile u8 *buff, u8 sector_no, u8 track_no, u8 head_
34        :"a"(0x0200|blocks), "b"(buff), "c"(track_no << 8 | sector_no), "d"(head_no << 8 | disk_no)
35      ); 
36  #endif
37 +  __asm__ __volatile__("pop %dx");
38 +  __asm__ __volatile__("pop %cx");
39 +  __asm__ __volatile__("pop %bx");
40 +  __asm__ __volatile__("pop %ax");
41    u8 ret_status = (num_blocks_transferred >> 8);
42    #ifdef MORE_ERR_MSG
43    NAME_VALUE(num_blocks_transferred)
44 @@ -524,7 +533,7 @@ int load_file_to_ram(int begin_cluster, int fat, u16 org_es, u16 es)
45  {
46    int r;
47    int r_sec = begin_cluster - 2 + bpb.root_dir_occupy_sector + bpb.root_dir_start_sector;
48 -  volatile u8 *buff = (u8*)LOAD_KERNEL_OFFSET;
49 +  u16 buff = LOAD_KERNEL_OFFSET;
50  
51    print_num(begin_cluster, "begin_cluster");
52    print_num(r_sec, "cluster sector no");
53 @@ -568,7 +577,7 @@ int load_file_to_ram(int begin_cluster, int fat, u16 org_es, u16 es)
54  #endif
55          if (read_sector_count == 65536/512)
56          {
57 -          buff = (u8*)LOAD_KERNEL_OFFSET;
58 +          buff = LOAD_KERNEL_OFFSET;
59  #ifdef MORE_ERR_MSG
60            print("\r\nmore than 64Kb\r\n");
61  #endif
62 @@ -664,7 +673,7 @@ void start_c()
63    head_no=0; // dh
64    disk_no=0; // dl
65  #endif
66 -  *buff = 0x1;
67 +  //*buff = 0x1;
68  
69    int r = read_sector(buff, sector_no, track_no, head_no, disk_no, 1);
70    init_bpb(buff, &bpb);

26 +  __asm__ __volatile__("push %eax");
27 +  __asm__ __volatile__("push %ebx");
28 +  __asm__ __volatile__("push %ecx");
29 +  __asm__ __volatile__("push %edx");
30  
31    __asm__ __volatile__ 
32      (
33 @@ -349,6 +354,10 @@ int __REGPARM read_sector(volatile u8 *buff, u8 sector_no, u8 track_no, u8 head_
34        :"a"(0x0200|blocks), "b"(buff), "c"(track_no << 8 | sector_no), "d"(head_no << 8 | disk_no)
35      ); 
36  #endif
37 +  __asm__ __volatile__("pop %edx");
38 +  __asm__ __volatile__("pop %ecx");
39 +  __asm__ __volatile__("pop %ebx");
40 +  __asm__ __volatile__("pop %eax");

似乎和 static 變數無關, 改成 push/pop 32 bit register 比較正常了。

git commit 03532548e7d57d660033e648c793a657ebe596de

似乎還得補上 push/pop %esi, %edi



 1 +  __asm__ __volatile__("push %esi");
 2 +  __asm__ __volatile__("push %edi");
 3    __asm__ __volatile__("push %eax");
 4    __asm__ __volatile__("push %ebx");
 5    __asm__ __volatile__("push %ecx");
 6 @@ -366,12 +369,15 @@ int __REGPARM read_sector(u16 buff, u8 sector_no, u8 track_no, u8 head_n
 7    __asm__ __volatile__("pop %ecx");
 8    __asm__ __volatile__("pop %ebx");
 9    __asm__ __volatile__("pop %eax");
10 +  __asm__ __volatile__("pop %edi");
11 +  __asm__ __volatile__("pop %esi");

git commit 38a3df774b25348aceffb479d731a5579641f595

我對在 c 語言使用 inline assembly 還不熟悉, 可能踩到什麼陷阱了。會加上 push/pop 這些暫存器只是我反組譯看到 c compiler 會用到這些暫存器, 所以加上。