Ci-joint un mémo que j'ai écrit pour créer un mini linux embarqué.
On fait demarrer une machine sur un noyau qui relaie vers un
RAMDisk. (google
RAMDisk, si ce concept est abstrait pour vous, ou mieux: man mkinitrd, en console).
Pour faire mes essais j'ai utilisé 2 machines et un boot réseau.
Bien sur, on peux directement booter sur un liveCD ou une cléf USB, si la carte mère le permet.
Je me suis beaucoup amusé avec ces essais, je vous encourage à le faire..
Vous pouvez utilisez un vieux disque dur dans un boitier USB pour simuler une cléf USB. C'est la même configuration. A partir de 200 M° ça devrait aller.
Je n'ai créer le
RAMDisk initial, je suis maintenant capable de le faire et j'envisage de tester la méthode Busybox (google busybox...) J'ai donc récuperé un initrd de ma distribution crée par "mkinitrd".
Je l'ai decompressé, étudié puis modifié.
On peut également faire ça avec le
RAMDisk d'un cd d'install.
Il s'agit d'une compression ramfs qui fonctionne ainsi:
- decompression:
# cramfs -x repertoire initrd
ou 'repertoire' sera crée à partir de initrd
- compression:
# mkcramfs repertoire initrd
ou 'repertoire' est un rep. contenant l'arborescence et initrd l'initrd qui sera produit.
Nous modifions l'arborescence suivant ce modele:
initrd
|
|--> /bin /sbin /lib /dev /etc /proc /sys /usr /var /mnt /tmp
Les repertoires /var /tmp /mnt ne sont pas indispensables,
de même sans /proc ou /sys le systeme demarrera.
Toutefois, je m'en servirai plus loin.
IL n'y a pas de repertoire /root ou /home, car la séquence d'authentification (getty-login) est zappé par un accès direct à /bin/bash en fin de init. De même, je n'utilise pas /etc/inittab dans cet exemple.
Le noyau 2.6 est compilé avec le support "cramfs",
il passera la main dès la fin de son chargement à l'executable /sbin/init,
(pas de linuxrc avec les cramfs).
Nous commençons par supprimer le fichier original (rm /sbin/init)
que nous remplaçons par ce modèle:
#!/bin/bash
export PATH:/bin:/sbin
mount -a
mount -t proc /proc proc
mount -t sysfs /sys sys
/bin/loadkeys /usr/share/keymaps/i386/azerty/fr-latin1.kmap.gz
echo "Bienvenue"
exec /bin/bash
Les executables "mount" et "echo" sont dèjà présents,
il faudra rajouter "loadkeys".
Un autre modèle que j'ai exploité pour utiliser un mass-storage USB comme système de fichier racine:
#!/bin/bash
export PATH=/sbin:/bin
modprobe uhci_hcd
sleep 5
modprobe usb-storage
sleep 5
mount -t ext3 /dev/sda1 /new_root
cd /new_root
pivot_root . /new_root/old_root
mount -t proc /proc /proc
mount -t sysfs /sys sys
/bin/loadkeys /usr/share/keymaps/i386/azerty/fr-latin1.kmap.gz
echo "Bienvenue"
exec /bin/bash
- Dans cet exemple il faut créer le rep. new_root à la racine de l'initrd.
Et il faut créer un rep /old_root sur le mass-storage USB
- Note: le mecanisme de pivot_root:
1) monter le nouveau système racine
2) s'y rendre (cd /new..)
3) créer un rep (ou bien il existe déjà et est vide)
4) pivot_root . /rep_crée
ou le point signifie "ici" et "/rep_crée" est l'endroit ou on "ejecte" l'ancien systeme, qui pourra être demonté.
CAD: "ici" devient "/", et l'ex "/" (le root=/dev/ram0
du bootloader) va à "/rep-crée".
- Dans cet exemple, les executables "pivot_root","modprobe" sont déjà présents, manquent "loadkeys" ainsi que "sleep".
- Manque également les modules USB que nous rajouterons.
- Le périphérique spécial "/dev/sda1"
Installer de nouveaux executables:
----------------------------------
A partir d'un système Linux complet, les executables sont copiés vers les repertoires équivalents du
RAMDisk, (/bin,/sbin).
Il convient d'utiliser un système avec la même version de noyau car nous allons recuperer des librairies et plus tard des modules.
Chaque executable utilise des librairies en langage C qu'il faudra recuperer.
Pour celà, il existe un outil: ldd.
Exemples:
ldd sleep:
/lib/tls/libm.so.6
/lib/tls/librt.so.1
/lib/tls/libc.so.6
/lib/ld-linux.so.2
/lib/tls/libpthread.so.0
ldd bash:
/lib/libncurses.so.5
/lib/tls/libdl.so.2
/lib/tls/libc.so.6
/lib/ld.linux.so.2
ldd ls:
/lib/tls/librt.so.1
/lib/libacl.so.1
/lib/tls/libc.so.6
/lib/tls/libpthread.so.0
/lib/ld-linux.so.2
/lib/libattr.so.1
Il faut copier: # cp /système_complet/lib/xxx /initrd/lib/ ,
pour chaques librairies, exeptées celles partagées et dèjà présentes avec un executable dèjà installé.
Le clavier AZERTY, necessite un peu plus de travail:
"fr-latin1.kmap.gz" necessite "loadkeys" et "gunzip" ainsi qu'une arboresence de repertoires:
ldd /bin/loadkeys
/lib/libcfont.so.0
/lib/libctutils.so.0
/lib/libconsole.so.0
/lib/tls/libc.so.6
/lib/ld-linux.so.2
ldd /bin/gunzip
/lib/tls/libc.so.6
/lib/ld-linux.so.2
# cp /bin/loadkeys (initrd)/bin ; cp /bin/gunzip (initrd)/bin et les libs...
# mkdir -p (initrd)/usr/share/keymaps/i386/azerty
# cp -rf /usr/share/keymaps/include (rm *latin2* *3* *4* sun* qwerty*) (initrd)/usr/share/keymaps/i386/
# cp /usr/share/keymaps/i386/azerty/fr-latin1.kmap.gz (initrd)/usr/share/keymaps/i386/azerty
************
- Dans le cas d'un pivot_root sur support USB, (clef,hdd etc..),
il faudra recuperer:
# cp -rf /lib/modules/2.6.xx/kernel/drivers/usb (initrd)/lib/modules/2.6.xx/kernel/drivers/
- Note: L'USB storage requiert le module SCSI (../drivers/scsi) sd_mod
- Note: certain chipset USB sont ohci_hcd et non pas uhci_hcd (ehci_hcd = USB2) ex: les cartes mères NEC, avec lequelles j'ai fait des tests d'image réseau.. Il faut: rmmod uhci_hcd puis modprobe ohci_hcd.
- Le module vfat requiert .../kernel/fs/nls
TODO : NET, PCMCIA et NFS ...
************
Le repertoire /dev
-------------------
Créer "/dev/sda1", pour le premier mass-storage USB:
# mknod /dev/sda1 b 8 1
J'ai également crée /dev/hda1 pour des tests en local.
# mknod /dev/hda1 b 3 1
- Note: pour identifier un périphérique spécial à partir d'un système complet:
# ls -l --color /dev/xx
bxxx--blabla x proprio (N°),(N°) /dev/xx
avec b = bloc ou c = caractère et N° ,N° = Majeur et mineur.
*****************
NOTES:
Le systeme de fichier cramfs pour l'initrd, possede une taille précise
definie dans le noyau (80M°) et que je n'ai pu modifier lors de la
compilation. Si l'on dépasse la taille de 80M°, le kernel panique avec
un message "big ramfs...".
L'initrd de l'exemple utilise 12 M° de l'espace alloué.
Il reste de la place...
Difference entre init et /sbin/init:
Ne pas confondre "init", lié avec une routine C du noyau et "init"
de /sbin/init.
Difference entre linuxrc et /sbin/init:
linuxrc est présent dans les initrd .gz et il est executé
AU DESSUS de /sbin/init. Dont le rôle est alors de lire /etc/inittab
et de lancer les scripts du runlevel par defaut.
********************
Boot NFS et Kernel:
------------------
Option 1:
a) Utilisation d'un noyau capable de monter directement un systeme
de fichier reseau par NFS.
Effectuer une compilation avec, (2.6):
device driver --> networking support --> networking option -->
* TCP/IP networking
* kernel level autoconfiguration
* DHCP support
* BOOTP support
file system --> network file system -->
* NFS file system
* Root file system on NFS
+ carte réseau EN DUR
+ /etc/fstab avec nfs
b) pxelinux.cfg/default contient:
LABEL linux # ex
KERNEL vmlinuz # ex.
APPEND ip=dhcp nfsroot=192.168.1.3:/root_fs
root=/dev/nfs init=/sbin/init
Rappel: PAS de pivot_root ni de /sbin/init (ou linuxrc)
Option2:
pxelinux.cfg/default lance un
RAMDisk
et un /sbin/init (ou linuxrc) qui pivote vers le partage NFS:
LABEL linux # ex.
KERNEL vmlinuz # ex.
APPEND initrd=initrd.img.gz
RAMDisk_size=8192
/sbin/init (ou linuxrc):
> charge les modules (eth0, nfs...)
> monte le partage (mount -t nfs...)
> cd /sysroot
> pivot_root . initrd
Exemple de (initrd)/sbin/init pour un montage NFS:
#!/bin/bash
export PATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/ usr/local/sbin:/usr/bin/X11"
mount -t proc /proc proc
mount -t sysfs /sys sys
/bin/loadkeys /usr/share/keymaps/I386/azerty/fr-latin1.kmap.gz
echo ""
echo "Bienvenue - Jean Ostos - Custom kernel"
echo ""
modprobe 3c59x # carte reseau
sleep 1
/sbin/ifconfig eth0 up
/sbin/ifconfig eth0 192.168.1.3
sleep 1
/sbin/modprobe nfs
sleep 1
/sbin/modprobe lockd
sleep 1
/sbin/modprobe sunrpc
sleep 1
mount -t nfs 192.168.1.16:/nfs /mnt
sleep 4
cd /mnt
sleep 1
/sbin/pivot_root . old_root/
sleep 1
exec /sbin/init
******************
Amusez vous bien, n'hésitez pas à nous faire part de vos essais...
J'ai fait des tests avec le serveur X et je travaille maintenant sur des mini distrib dédié à une seule tache...
Jean-svg