kendi hafif initramfs'nizi yapın

Başlatan unixmania, 29 Şubat 2016 - 14:06:01

« önceki - sonraki »

0 Üyeler ve 2 Ziyaretçi konuyu incelemekte.

unixmania

Öğrenmeye/kurcalamaya meraklı arkadaşlar için aşağıda kendi hafif initramfs' nizi nasıl yaparsınız onu anlattım.

Sıradışı bir yol izledim ve initramfs'yi sadece C dili kullanarak tasarladım. initrd.c dosyası:


int main(int argc, char *argv[])
{
int cfd;
char* modules[] = {"scsi_mod.ko", "sd_mod.ko", "libata.ko" , "libahci.ko", "ahci.ko",  "f2fs.ko",  0};  // Sıra önemli, bağımlılık sırası!

for (char i = 0; modules[i] != 0; i++) {
cfd = syscall(2, modules[i], 0);                    //open(modules[i], 0)
syscall(313, cfd, "", 0);                                 //finit_module(cfd, "", 0)
syscall(3, cfd);                                             //close(cfd)
}

syscall(83, "root", 0755);                                    //mkdir("root", 0755)
syscall(133, "nod", 060755, 0x802);                   //mknod("nod", 060755, 0x802)
syscall(165, "nod", "root", "f2fs", 1024, 0);         //mount("nod", "root", "f2fs", 1024, 0)
syscall(80, "root");                                              //chdir("root")
syscall(161, ".");                                                 //chroot(".");

syscall(59, "/bin/init", (char*[2]) {"/bin/init", 0}, 0);     //execve("/bin/init", (char*[2]) {"/bin/init", 0}, 0)
}
   

Derlemek için:

1- Bir klasör oluşturun.Adı farketmez.İçi boş olsun.

2- Yukarıdaki kodu initrd.c diye oluşturduğunuz boş klasörün içine atın.

3- char* modules[] = diye başlayan satır initrd dosyasına dahil etmek istediğiniz kernel modüllerini belirtir.Bunların sırası önemlidir. Kendi sisteminize özgü modülleri

belirtmelisiniz. Benim root dosya sistemi "f2fs"  sizinti ext4 ise f2fs yi silip yerine ext4 yazmalısınız. "modinfo ext4" diyerek ext4 ün bağımlılıklarına bakıp önce

bağımlılıklarını yazmalısınız. "scsi_mod.ko", "sd_mod.ko", "libata.ko" , "libahci.ko", "ahci.ko" bunlar harddiski tanımak için lazım, dokunmayın!

4- syscall(133, "nod", 060755, 0x802) burdaaki 0x802  /dev/sda2 oluyor  0x803=/dev/sda3 olur. Ona göre sizin root hangisiyse onu yazın.

5- char* modules[] = buraya yazdığınız modülleri oluşturduğunuz klasörün içine kopyalayın. Modüller ko.gz uzantılıdır. gzip ile açmalısınız kopyaladıklarınızı.Böylece

gz uzantısı gider .ko uzantısı kalır.

6- Klasörü hazırlama işlemi bitti. İşte oluşturduğum klasörün içi:


[me@localhost ramfs]$ ls
ahci.ko  f2fs.ko  initrd.c  libahci.ko  libata.ko  scsi_mod.ko  sd_mod.ko
[me@localhost ramfs]$


7- Sonra aynı klasörde terminal açıp :


gcc -O3 -static initrd.c -o init


komutunu verin "init" adında dosya oluşacak.

8- En son initrd' yi oluşturmak için aynı dizinde:


[root@localhost ramfs]# find . -print0 | bsdcpio -o -0 -H newc > /boot/benimramfs.img


komutunu yürütün. /boot dizini diğer initramfs' lerin bulunduğu dizindir.Değilse ona göre düzeltin. /boot altında benimramfs.img oluşmuş olmalı.

9- Test etmek için grup veya her ne kullanıyorsanız yeni bir "title" oluşturup  bu title'ın kernel komut satırını initrd=benimramfs.img diye düzenleyin.

TEHLİKE: KESİNLİKLE YENİ BİR BAŞLIK (title) oluşturun. Halihazırda kullandığınıza dokunmayın.

* her şey yolunda gidirse 2MB civarında bir initrdniz olur(şıkıştırılmamış).

Lüzumsuz bir şey olmadığından sistemin açılışı hızlanabilir.

Buda yukardaki initramfs' nin sadece assembly dili ile yazılmış versiyonu.Canavar gibi çalışıyor. Şekil olsun diye veriyom sadece.


section .data
cmd db "/bin/init", 0
modules do 'scsi_mod.ko', 'sd_mod.ko', 'libata.ko' , 'libahci.ko', 'ahci.ko', 'f2fs.ko', 'serio.ko', 'i8042.ko', 'libps2.ko', 'atkbd.ko'
vars  dq "nod", "/r", "f2fs", ""

section .text
global _start

_start:
mov rax, 83
mov rdi, vars+8
mov rsi, 755o
syscall

mov rax, 133
mov rdi, vars
mov rsi, 60755o
mov rdx, 2050
syscall

mov rcx, 10
mov rbx, modules
L1:
push rcx

mov rax, 2
mov rdi, rbx
mov rsi, 0
syscall

mov rdi, rax 
mov rax, 313   
mov rsi, vars+24
mov rdx, 0
syscall

mov rax, 3
syscall

add rbx, 16
pop rcx
loop L1

mov rax, 165
mov rdi, vars
mov rsi, vars+8
mov rdx, vars+16
mov r10, 1024
mov r8, 0
syscall

mov rax, 80
mov rdi, vars+8
syscall

mov rax, 161
mov rdi, vars+8
syscall

mov rax, 59
mov rdi, cmd 
lea rsi, [rsp + 8]
mov rdx, 0
syscall


TEHLİKE: Yukarıda anlatılanlar deneyimli kullanıcılar içindir.

NOT: assembly nasm sentaksındadır.

NOT2: syscall sistem çağrısı yapma fonksiyonudur. Headerleri include etmemek için onu kullandım.

ahmet_matematikci

eline sağlık hocam da initrdniz şeysi ne işe yarıyor ???
♥ Kız tavlamak için kahraman olmak gerekmez. Doğru kadın zaten sizi kahraman yapar ;)

unixmania

Bilgisayar boot ederken kullanılan dosya sistemi. İşi kernelin root'u bağlamasını sağlamak.

Türkçe wikide bulamadım. Burada tarif etmiş.

https://wiki.ubuntu.com/Initramfs

ahmet_matematikci

Çok soru soruyorum cahilliğime ver.
Kernel rootu bağlayınca ne oluyor ki ??? ???
♥ Kız tavlamak için kahraman olmak gerekmez. Doğru kadın zaten sizi kahraman yapar ;)

unixmania

sistem boot etmiş oluyor. root' u bağlamak: kök dosya sistemini(/dev/sda2 falan)  bağlamak anlamında (mount etmek) olup bilgisayarın açılması için zorunlu bir prosestir.

ahmet_matematikci

Hazırda var olan sistemlerden senin kinin farkı ne hocam.
Artı olarak senin kodlar ne kazandırıyor.
♥ Kız tavlamak için kahraman olmak gerekmez. Doğru kadın zaten sizi kahraman yapar ;)

Sh4oTT

Benim de sormak istedigim

gcc -O3 -static initrd.c -o initBurdaki -03 ve -static ne anlama geliyor ? Neden normal derlemediniz bu parametreler ne anlama geliyor? Tssekkurler :)

Felâsife

Alıntı yapılan: ShaoDownLiNuP - 29 Şubat 2016 - 19:13:23
Burdaki -03 ve -static ne anlama geliyor ? Neden normal derlemediniz bu parametreler ne anlama geliyor?
Burası işinize yarayabilir.
Maceraya hazır mısın!  Bir BSD almaz mısın?

Amenofis

Alıntı yapılan: ShaoDownLiNuP - 29 Şubat 2016 - 19:13:23
Benim de sormak istedigim

gcc -O3 -static initrd.c -o initBurdaki -03 ve -static ne anlama geliyor ? Neden normal derlemediniz bu parametreler ne anlama geliyor? Tssekkurler :)

Programı geliştirme esnasında debug modda derleriz ki hataları daha kolay ayıklayabilelim (gcc -g ...)

Tamamlandıktan sonra optimizasyonlar açılarak tekrar derlenir, bunu da -Ox parametresi ile yaparız. x opt seviyesi, 3 pek tavsiye edilmez, programın boyutunu şişirir. Ben kullanmam şahsen. Tabi bu kadar kısa bir programda -O0 ile -O3 arasında hiçbir fark olmaz.

-static ise kütüphaneleri paylaşımlı olarak değil statik olarak bağlar. Böylece bağımlılıkları programa dahil etmiş olursun. Özel bir sebebi yoksa kaçınılmalıdır çünkü program boyutu çok fazla şişer. İlla yapılacaksa release modda yani uygulama tamamlandıktan sonra yapılmalı.

unixmania

#9
Alıntı yapılan: ahmet_matematikci - 29 Şubat 2016 - 16:02:22
Hazırda var olan sistemlerden senin kinin farkı ne hocam.
Artı olarak senin kodlar ne kazandırıyor.

1- Boyut: İnitramfs boyutu 2MB' ta düştü.Hemde şıkıştırılmamış halde. Daha önce gzip formatında şıkıştırılmış halde 5.5MB idi.

3MB farkedermi.Tabii ki farketmez. Belki embedded donanımda farkeder.İnitramfs içindeki bütün ıvır zıvır gitti.Sadece 5-6 tane kernel modülü(*.ko dosyaları) ve

init dosyam kaldı. Sade ve temiz:)

2- Hız: Çalıştırılabilir birçok bash dosyaları gitti yerine sadece bir tane derlenmiş  C kodu geldi.Bilgisayar derlenmiş(binary/ikili) C kodunu bash dosyalarından

"atıyom" 10 kat daha hızlı yürütür. Ayrıca sadece root'u bağlamaya yetecek kadar modül/işlem. Gereksiz müdüller/işlemler ayıklandı.

Eğer Allah'ın seçkin kulu iseniz açılma zamanınızın 15 saniyeden 2-3 saniyeye düşmesi işten bile değil;)    (deneyime tabidir)

Alıntı yapılan: ShaoDownLiNuP - 29 Şubat 2016 - 19:13:23
Benim de sormak istedigim

gcc -O3 -static initrd.c -o initBurdaki -03 ve -static ne anlama geliyor ? Neden normal derlemediniz bu parametreler ne anlama geliyor? Tssekkurler :)

-O3: Kodu derlerken optimize eder.Bu kadar kısa bir programda bir işe yarar mı? Bilmiyorum, muhtemelen pek * bir şey katmaz.

-static: Dedim ya yukarıdaki initramfs'de /usr yok, /etc yok hiçbir library dosyası yok.Yukarıdaki kodun çalışması için zorunlu olan

tek library(kütüphane) dosyası libc.so 'dur."-statik" opsiyonu: "zorunlu library dosyalarını derlenmiş dosyayla birleştir, hiçbir harici library dosyasına

ihtiyaç duymadan çalışabilen çalıştırılabilir dosyayı oluştur" anlamındadır. Assemby ile paylaştığım kod libc.so 'ya bile ihtiyaç duymaz.

NOT: İsteyen yukardaki 8-9 adımı bir bash scripti yapıp, işin hamallık kısmını bash'a yıkabilir.

ahmet_matematikci

@unixmania detaylı açıklaman için teşekkür ederim. Ellerine sağlık
♥ Kız tavlamak için kahraman olmak gerekmez. Doğru kadın zaten sizi kahraman yapar ;)

cokomoko

Eğer açılış hızlanıyorsa denemeye değer, eline sağlık, müsait bir zamanda deneyeceğim.
Bu  arada sizin açılış kaçtan kaça düştü?
''Eğer 386BSD ben Linux'a başladığımda var olsaydı, Linux büyük bir olasılıkla olmazdı."
........................Linus Torvalds..........................
İnsanın aradığı sadece huzur ve mutluluktur, 1 numara olmak yalnız kalmak demektir ve 1 numara kalmak için birçok şeyi feda etmek zorunda kalırsın...

Sh4oTT

Bilgiler icin tesekkurler arkadaslar :)

unixmania

Alıntı yapılan: cokomoko - 01 Mart 2016 - 19:16:53
Bu  arada sizin açılış kaçtan kaça düştü?

Benim çıktı böyle.ANCAK belirtmeliyim. Bu ultrabooktur, SSD var, ben deneyimliyim, benim için zorunlu olmayan her şeyi kapadım, servisler minimal.


~ systemd-analyze
Startup finished in 7ms (firmware) + 132us (loader) + 1.240s (kernel) + 669ms (userspace) = 1.917s
236ms dev-sda2.device
           213ms nett.service
            55ms systemd-user-sessions.service
            34ms systemd-journald.service
            28ms user@1000.service
            28ms boot.mount
            25ms systemd-udevd.service
            18ms systemd-udev-trigger.service
            17ms systemd-sysctl.service
            15ms systemd-tmpfiles-setup.service
            12ms systemd-tmpfiles-setup-dev.service
            12ms systemd-logind.service
            11ms dev-hugepages.mount
             8ms sys-kernel-config.mount
             8ms systemd-tmpfiles-clean.service
             8ms systemd-remount-fs.service
             8ms tmp.mount
             7ms dev-mqueue.mount
             5ms systemd-journal-flush.service
             4ms systemd-backlight@backlight:intel_backlight.service
             3ms kmod-static-nodes.service
             3ms systemd-random-seed.service
             3ms systemd-rfkill@rfkill0.service
             2ms systemd-rfkill@rfkill1.service


1.240s (kernel) --> Bu normal değildir. Kernelin initializasyonundaki rahatsızlığı işaret etmektedir. Normalde kernelin hakkı 100-200 milisaniye olması lazım.

Milletin paylaştığı çıktılarda bunu görebilirsiniz. Kendi kernelimi kendim derlesem belki düzelir. O kadar üstüne düşmedim.

Hali hazırda açılışında sıkıntı yoksa(20-30 saniyelerden bahsediyom) yukardaki yöntemden mucize bekleme!

Bu arada çıktı archlinux'tan.

cokomoko

#14
ext4 kullanan biri olarak 3 sorum var:
1-modinfo ext4'e baktığımda şunlar görünüyor:
└──>>modinfo ext4
filename:       /lib/modules/4.3.3-8-lqx/kernel/fs/ext4/ext4.ko.gz
license:        GPL
description:    Fourth Extended Filesystem
author:         Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others
alias:          fs-ext4
alias:          ext3
alias:          fs-ext3
depends:        mbcache,jbd2,crc16
intree:         Y
vermagic:       4.3.3-8-lqx SMP preempt mod_unload modversions
parm:           num_prealloc_crypto_pages:Number of crypto pages to preallocate (uint)
parm:           num_prealloc_crypto_ctxs:Number of crypto contexts to preallocate (uint)


bu 3 modülü char* modules'in en başına mı yazacağım, yoksa ext4.ko'dan önce mi yazacağım?
2-
Alıntı Yapsyscall(133, "nod", 060755, 0x802) burdaaki 0x802  /dev/sda2 oluyor  0x803=/dev/sda3 olur. Ona göre sizin root hangisiyse onu yazın.
Benim root dizini /dev/sdb9 üzerine kurulu, 0x819=/dev/sdb9 mu oluyor?
3-
Alıntı Yapchar* modules[] = buraya yazdığınız modülleri oluşturduğunuz klasörün içine kopyalayın. Modüller ko.gz uzantılıdır. gzip ile açmalısınız kopyaladıklarınızı.Böylece
gz uzantısı gider .ko uzantısı kalır.
demişsiniz.
Ama bu modülleri nereden alıp kopyalayacağız, modüllerin hepsini tek tek bulup, .ko şeklinde mi çıkartacağız?(galiba modülleri kernel'in ilgili dizinlerinden alıyoruz)
''Eğer 386BSD ben Linux'a başladığımda var olsaydı, Linux büyük bir olasılıkla olmazdı."
........................Linus Torvalds..........................
İnsanın aradığı sadece huzur ve mutluluktur, 1 numara olmak yalnız kalmak demektir ve 1 numara kalmak için birçok şeyi feda etmek zorunda kalırsın...

unixmania

Alıntı yapılan: cokomoko - 05 Mart 2016 - 20:28:42
1-bu 3 modülü char* modules'in en başına mı yazacağım, yoksa ext4.ko'dan önce mi yazacağım?

2-Benim root dizini /dev/sdb9 üzerine kurulu, 0x819=/dev/sdb9 mu oluyor?

3- modüllerin hepsini tek tek bulup, .ko şeklinde mi çıkartacağız?(galiba modülleri kernel'in ilgili dizinlerinden alıyoruz)

1- ext4.ko'dan önce yazacan. Onlarında bağımlılığı varmı bakacan:)

2-Hayır. Galiba 0x825 olacak. Orada disk bilgilerinde bir yerde yazar. Şuan winden yazıyorum. Biri söyleyiversin deviceID nerde yazar.

udevadm info /dev/sdb9    olabilir.

3-Aynen tek tek, kernel dizininden (/usr/lib/modules/falan). Eziyettir biliyorum.Onun için biri sevabına bash scriptine çevirse şunu.

unixmania

#16
Kendim bash scripte çevirdim. İşte:


MODULES="ahci sd_mod ext4"
for mod in $MODULES; do
declare deps=$(modinfo -F depends $mod)
echo $deps

declare tmp="$mod.ko.gz"
cp $(find /usr/lib/modules/$(uname -r)/kernel -name $tmp) .
gzip -d $tmp 
done
gcc -static inird.c -o init
find . -print0 | bsdcpio -0 -o -H newc > /boot/ramdisk



Yalnız bağımlılık işini henüz halledemedim.Şöyle ki

modinfo -F depends ext4


komutu modül bağımlılıklarını virgülle ayırarak veriyor.Komutun verdiği çıktıyı (deps'e atadım) boşlukla ayrılmış formata çevirmek lazım.

Aynı yukarıdaki MODULES değişkeninde olduğu gibi.Zor bir şey sayılmaz ama henüz halledemedim.

C koduda bu scriptin içine alınabilir. Böylece C kodu için ayrı bir dosya oluşturma zorunluluğu kalkar.

/dev/sdXY yi otomatik deviceID ye çeviren kod eklenebilir.

/dev/sdXY yi scripti yürütürken argüman olarak verme işlevselliği eklenebilir.

ahmet_matematikci

♥ Kız tavlamak için kahraman olmak gerekmez. Doğru kadın zaten sizi kahraman yapar ;)

unixmania

Güncelleme:

1-* her şey tek bir python scriptine indirgendi.

2-İnitramfs'yi oluşturmak (* her şey için) için tek bir komut yeterli: bu scripti yürütmek.

3-Modüllerin yazılış sırası önemli değil, ayrıca yazılan modüllerin bağımlılıklarını otomatik bulup ekler.


#!/usr/bin/python

import subprocess, os

path = "/usr/lib/modules/" + subprocess.getoutput("uname -r")
modules  = ["sd_mod", "ahci", "ext4"]

os.mkdir("initrd")
os.chdir("initrd")

def collect(mod, ret):
zz = subprocess.getoutput("modinfo -F depends " + mod)
if len(zz):
zz = zz.split(',')
for j in zz:
if j not in ret:
ret.insert(0,j)
collect(j, ret)

def ordered(mods):
ret = []
ln = len(mods)
for i in mods:
zz = subprocess.getoutput("modinfo -F depends " + i)
if len(zz) == 0:
ret.insert(0,i)
else:
if len(ret) == 0:
ret.insert(0,i)
else:
for j in ret:
tt = subprocess.getoutput("modinfo -F depends " + j)
if len(tt):
tt = tt.split(',')
if i in tt:
ret.insert(ret.index(j), i)
break
if i not in ret:
ret.append(i)
return ret

ret  = []
for i in modules:
collect(i, ret)

ret += modules
ret = ordered(ret)

cmod = "{"
for i in ret:
cmod += '"' + i + '.ko",'
j = subprocess.getoutput("find " + path + " -name " + i + ".ko.gz")
subprocess.call(["cp", j, "."])
subprocess.call(["gzip", "-d", i + ".ko.gz"])

cmod += "0};"

cfile = '''int main(int argc, char *argv[])
{{
int cfd;
char* modules[] = {}

for (char i = 0; modules[i] != 0; i++) {{
cfd = syscall(2, modules[i], 0);                   
syscall(313, cfd, "", 0);                               
syscall(3, cfd);                                           
}}

syscall(83, "root", 0755);                                   
syscall(133, "nod", 060755, 0x802);                   
syscall(165, "nod", "root", "f2fs", 1024, 0);         
syscall(80, "root");                                             
syscall(161, ".");                                                 

/*while (1){{
char cha = getchar();
perror("");
if (cha == 27) break;
}}*/

syscall(59, "/usr/bin/init", (char*[2]) {{"/usr/bin/init", 0}}, 0);
}}'''

cfile = cfile.format(cmod)

fd = os.open("init.c", os.O_RDWR | os.O_CREAT)
os.write(fd, cfile.encode())
os.close(fd)

subprocess.call(["gcc", "-static", "-O2", "-s", "init.c", "-o", "init"])

#os.remove("init.c")

p1 = subprocess.Popen(["find", ".", "-print0"], stdout=subprocess.PIPE)
p2 = subprocess.Popen(["bsdcpio", "-o", "-H", "newc", "-F", "../ramdisk"], stdin=p1.stdout)
p2.communicate()


Oluşan ramdisk isimli dosya bizim initramfs dosyamız oluyor.

cokomoko

Hmm bu güzel oldu, benim de aklımda idi bu konu yedeğini dealmıştım gerek kalmadı bu scriptle.
''Eğer 386BSD ben Linux'a başladığımda var olsaydı, Linux büyük bir olasılıkla olmazdı."
........................Linus Torvalds..........................
İnsanın aradığı sadece huzur ve mutluluktur, 1 numara olmak yalnız kalmak demektir ve 1 numara kalmak için birçok şeyi feda etmek zorunda kalırsın...

betseg

Bunun mkinitcpio'ya göre iyi yönleri var mı? Yoksa daha geliştirilmesi gerekiyor mu? İkisini birlestirsek ortaya iyi bir şey çıkar mı? :)

unixmania

Alıntı yapılan: betseg - 18 Nisan 2016 - 20:30:26
Bunun mkinitcpio'ya göre iyi yönleri var mı? Yoksa daha geliştirilmesi gerekiyor mu? İkisini birlestirsek ortaya iyi bir şey çıkar mı? :)

Yukarda da dedim: bunda bir kum tanesi kadar gereksiz bir sey yok. Zadece root'u baglamaya yetecek kadar: zorunlu 3-5 modul.

Bu moduller size ozel. Yani bu scripti kullanmak icin 'modules=' degiskenini kendi donaniminiza gore duzenlemelisiniz.

Ancak yukarda yazdigim degistirmeden bile kullanicilarin %50-70 inin isini gorur.Zaten root'u bagladiktan sonra systemd diger modulleri kendi otomatik yukler.

Onemli olan root'u baglamak(Kok dosya sistemini mount etmek).

Ayrica '/sbin/init' yukarda goruldugu gibi C ile yazildi. Hiz acisindan farkeder.

mkinitcpio bash ile yazilmis , bu python ile; python daha 'karizma' duruyo disardan bakinca;)

mkinitcpio'nun 20-30 dosya ve bilmem kacyuz satir kod ile yaptigi isi ben yukarda 50-100 satir kod ile yaptim. Is ayni is.

Bence script bu haliyle mkinitcpio yerine kullanilabilir. mkinitcpionun sadece /etc/mkinitcpio.conf diye bir config dosyasi var. Moduller ordan ayarlaniyor.

Bunda bizzat scriptin kendisinden duzenleniyor.

Ayrica istediginiz herangi bir dosyayi initrd icine dahil ettirme ozelligi var. Ancak benim zaten bu yontemi bulma amacim herseyi dahil etmekten kacinmak.