Внедрение 9load в LinuxBIOS
LinuxBIOS поддерживает большое количество разных вариантов «загрузок», к примеру, загрузка ELF образов из памяти FLASH. В этом документе описывается процедура внедрения DOS программы 9load в FLASH, которая позволит загружать узлы как выделенные Plan 9 CPU узлы.
ПРИМЕЧАНИЕ: за дополнительной информацией посетите: http://www.acl.lanl.gov/plan9/flash/.
Этот документ поможет вам настроить загрузку Plan 9 из LinuxBIOS. Он состоит из таких частей:
0. Преамбула
1. Настройка — с чего начать. Файловая организация Plan 9 и Linux
2. Объяснение исходного кода — diff-файлы к исходному коду 4-ой версии Plan
9 с комментариями
3. Исходный код
Преамбула
В документе обсуждаются изменения, подвергнув которым исходный код Plan 9, можно получить хотя бы одну машину, загружающуюся из LinuxBIOS. Целью проекта является создание автономного CPU сервера Plan 9, которому не требуются перемещаемые части. Большая часть работы выполнена Роном Майнничем (Ron Minnich).
1. Настройка
Для удачной модификации исходного кода требуются следующие вещи:
1.1 Сеть Plan 9 (включая файловые серверы, CPU серверы и терминалы
1.1.1 Автономный терминал Plan 9, так как сама настройка довольно хитрая
1.2 Исходный код Plan 9 (можно получить из сети Plan 9 и/или стандартной установки
системы)
1.3 Linux машина (используется для компиляции LinuxBIOS)
1.4 Аппаратное обеспечение, на котором может работать LinuxBIOS
1.5-9 Немного терпения
Настройка Plan 9
В настройке используется поддержка концепции союзных каталогов. Она дает возможность хранения только тех файлов, которые мы модифицируем в локальном каталоге, и связываем их при необходимости на верхушке стандартного дерева ядра (в /sys/src/)… Фактически, это происходит в специальном пространстве имен, которое может использоваться в едином терминальном окне (или же, в целом сеансе rio на CPU сервере) для представления скромной среды разработки, тем временем остальная часть экрана, сеанс или терминалы содержат общий, не разработческий вид системы. В конце концов, это позволяет нескольким разным разработчикам работать в одно и то же время (скоро будет показан пример этого) — компиляция ядер в одном окне, загрузчиков 9load в другом, при этом в третьем окне будет видно не модифицированное дерево ядра. Все в одном каталоге.
Каким образом все это работает
В двух словах, когда запускается LinuxBIOS, он выполняет поиск и загрузку загрузчика Plan 9 (9load замаскирован как образ elf32, таким образом, он распознается LinuxBIOS), затем 9load вызывает ядро или же другие варианты загрузки, закачивает, извлекает его и выполняет переход на него. Вуаля.
Детали ниже:
Компиляция (сборка) образа 9load, приспособленного для работы с LinuxBIOS:
p9% lbbind # связывает дерево разработки… p9% mk 9loadlb # в mkfile со специальной 8a -DLinuxBios -o ll.8 l.s # конфигурацией для linuxbios 8c -FVw -I. alarm.c # ядер по требованию 8c -FVw -I. cga.c # определение и связывание 9load 8c -FVw -I. clock.c # по адресу 0x800000 8c -FVw -I. console.c 8c -FVw -I. dosboot.c 8c -FVw -I. donprint.c 8c -FVw -I. devfloppy.c 8c -FVw -I. dma.c 8c -FVw -I. ilock.c 8c -FVw -I. kbd.c 8c -FVw -I. queue.c 8c -FVw -I. trap.c 8c -FVw -I. 8250.c warning: 8250.c:130 param declared and not used: arg 8c -FVw -I. apm.c 8c -FVw -I. boot.c 8c -FVw -I. devpccard.c 8c -FVw -I. conf.c 8c -FVw -I. devi82365.c 8c -FVw -I. devsd.c 8c -FVw -I. inflate.c 8c -FVw -I. load.c warning: load.c:159 no return at end of function: myboot load.c:280 function args not checked: pcihinv 8c -FVw -I. memory.c 8c -FVw -I. part.c 8c -FVw -I. pci.c 8c -FVw -I. sdata.c 8c -FVw -I. sdmylex.c 8c -FVw -I. sd53c8xx.c 8c -FVw -I. sdscsi.c 8c -FVw -I. bootp.c 8c -FVw -I. ether.c 8c -FVw -I. ether2114x.c 8c -FVw -I. ether2000.c 8c -FVw -I. ether589.c 8c -FVw -I. ether79c970.c 8c -FVw -I. ether8003.c 8c -FVw -I. ether8139.c 8c -FVw -I. ether82557.c 8c -FVw -I. ether83815.c 8c -FVw -I. ether8390.c 8c -FVw -I. etherec2t.c 8c -FVw -I. etherelnk3.c
-
8l -o 9loadlb -H3 -T0x80800000 -l ll.8 alarm.8 cga.8 clock.8 console.8 dosboot.8
donprint.8 devfloppy.8 dma.8 ilock.8 kbd.8 queue.8 trap.8 8250.8 apm.8 boot.8
devpccard.8 conf.8 devi82365.8 devsd.8 inflate.8 load.8 memory.8 part.8 pci.8
sdata.8 sdmylex.8 sd53c8xx.8 sdscsi.8 bootp.8 ether.8 ether2114x.8 ether2000.8
ether589.8 ether79c970.8 ether8003.8 ether8139.8 ether82557.8 ether83815.8
ether8390.8 etherec2t.8 etherelnk3.8 -lflate -lc
ls -l 9loadlb
--rwxr-xr-x M 9 andrey andrey 178320 Jun 20 11:34 9loadlb
p9%
9loadlb — это специальная конфигурация в mkfile, которая
#определяет «LinuxBIOS» в течение компиляции и связывает 9loadlb по адресу 0x800000 (отсюда начинается переход LinuxBIOS).
Следующий шаг — копирование 9loadlb на linux машину:
fbsd$ scp plan9:src/boot/pc/9loadlb ../9load.800000 andrey@plan9.acl.lanl.gov's password: 9loadlb 100% |*****************************| 174 KB 00:00 fbsd$
Далее запускаем сценарий mymk из mkelf:
snares$ pwd /users/andrey/kern/mkelf snares$ ./mymk #!/bin/sh -v cd 9load cp ~/kern/9load.800000 . make all4 ./mkas < 9load.800000 > 9l.s as -o 9l.o 9l.s ld -T elfImage.lds.800000 -o 9l.elf 9l.o ld: warning: cannot find entry symbol startup_32; defaulting to 00800000 cp 9l.elf .. cd ..
-
bin/mkelfImage --kernel=9l.elf
Running gcc -O2 -DDEFAULT_ROOT_DEV='(((0x3<<8)| 0))' -DDEFAULT_COMMAND_LINE='""' -DDEFAULT_PROGRAM_VERSION='""' -c /users/andrey/kern/mkelf/share/mkelfImage/elf32-i386/convert_params.c -o /am/mother-v2-e5/vol/vol0/u0/andrey/kern/mkelf/convert_params_6384.o
Running gcc -O2 -DDEFAULT_ROOT_DEV='(((0x3<<8)| 0))' -DDEFAULT_COMMAND_LINE='""' -DDEFAULT_PROGRAM_VERSION='""' -c /users/andrey/kern/mkelf/share/mkelfImage/elf32-i386/head.S -o /am/mother-v2-e5/vol/vol0/u0/andrey/kern/mkelf/head_6384.o
Running ld -o elfImage.fat -T /users/andrey/kern/mkelf/share/mkelfImage/elf32-i386/elfImage.lds /am/mother-v2-e5/vol/vol0/u0/andrey/kern/mkelf/kernel_piggy_6384.o /am/mother-v2-e5/vol/vol0/u0/andrey/kern/mkelf/ramdisk_piggy_6384.o /am/mother-v2-e5/vol/vol0/u0/andrey/kern/mkelf/convert_params_6384.o /am/mother-v2-e5/vol/vol0/u0/andrey/kern/mkelf/head_6384.o Running ld -o elfImage.fat -T /users/andrey/kern/mkelf/share/mkelfImage/elf32-i386/elfImage.lds /am/mother-v2-e5/vol/vol0/u0/andrey/kern/mkelf/kernel_piggy_6384.o /am/mother-v2-e5/vol/vol0/u0/andrey/kern/mkelf/ramdisk_piggy_6384.o /am/mother-v2-e5/vol/vol0/u0/andrey/kern/mkelf/convert_params_6384.o /am/mother-v2-e5/vol/vol0/u0/andrey/kern/mkelf/head_6384.oBFD: elfImage.fat: warning: Empty loadable segment detected checksum: dc7c echo done done
Сценарий порядком уродлив, но нам незачем красота… Вы увидите его ниже, или в linux bundle… Следующий шаг — копирование (команда scp) 9load (замаскированный под elfImage) в то место, откуда он может быть записан на flash:
fbsd$ scp elfImage plan9:/386/9pcblah andrey@plan9.acl.lanl.gov's password: elfImage 100% |*****************************| 190 KB 00:00 scp: can't wstat /386/9pcblah: wstat -- attempt to change qid.vers fbsd$
Если вы видите сообщения об ошибках — просто игнорируйте их… Dhcp сервер будет проинструктирован работать с /386/9pcblah как с ядром и отвечать на запросы bootp от машины, на которой выполняется работа (запрос основан на ethernet адресе машины).
ПРИМЕЧАНИЕ: если вы уверены в том, что 9load подходит вам, попросите Рона записать его вам. В этом случае вам нужно будет лишь поместить ядро 9pccpu в /386/9pcblah :)
Файловая организация
Создайте каталог $home/src для хранения всех модифицируемых файлов, затем в нем создайте организацию каталогов /sys/src, у меня оказалось три каталога: /sys/src/9, /sys/src/boot, /sys/src/libauthconfig, после этого рекурсивно создайте все оставшиеся каталоги, вот что получилось у меня:
p9% du /usr/andrey/src | awk '{print $2}' /usr/andrey/src/9/pc /usr/andrey/src/9/ip /usr/andrey/src/9/alphapc /usr/andrey/src/9/bitsy /usr/andrey/src/9/boot /usr/andrey/src/9/port /usr/andrey/src/9/mtx /usr/andrey/src/9 /usr/andrey/src/libauthsrv /usr/andrey/src/boot/alphapc /usr/andrey/src/boot/arm /usr/andrey/src/boot/pc /usr/andrey/src/boot /usr/andrey/src/cmd/aux/vga /usr/andrey/src/cmd/aux /usr/andrey/src/cmd/auth/factotum /usr/andrey/src/cmd/auth/lib /usr/andrey/src/cmd/auth/secstore /usr/andrey/src/cmd/auth /usr/andrey/src/cmd /usr/andrey/src p9%
Далее если вы хотите отредактировать /sys/src/9/pc/pci.c, выполните команду:
cp /sys/src/9/pc/pci.c $home/src/9/pc/pci.c
Сценарии
Несколько сценариев используются для автоматизации процесса связывания и облегчения вашей жизни. Помните, что после загрузки машина будет находится в состоянии «вне разработки», например, она не знает что вы сделали модификации в исходном тексте ядра — поэтому вам нужно сообщить ей об соответствующем изменении пространства имен, так что после введения вами mk в /sys/src/9/pc она скомпилирует ваши собственные файлы взамен всех других. Сценарии сами сделают модификации в пространстве имен, вам лишь остается выполнить их перед тем как вы начнете работу над кодом. Вот эти сценарии (они отличаются поскольку один выполняет связывание $home/src/9 как ядерного дерева — я использую его для написания драйверов поддержки нескольких графических карт, т.е. не LinuxBIOS ядер) а другой связывает $home/src/linuxbios/, который эквивалентен $home/src/9, но файлы в нем LinuxBIOS-связанные. Скопируйте сценарии в $home/bin/rc и проделайте над ними chmod 755:
p9% cat /usr/andrey/bin/rc/kbind #!/bin/rc # выполняет связывания для исходного текста ядра не-linuxbios # и исходных текстов 9load linuxbios # 9 bind -cb $home/src/9/pc /sys/src/9/pc bind -cb $home/src/9/ip /sys/src/9/ip bind -cb $home/src/9/alphapc /sys/src/9/alphapc bind -cb $home/src/9/bitsy /sys/src/9/bitsy bind -cb $home/src/9/boot /sys/src/9/boot bind -cb $home/src/9/port /sys/src/9/port bind -cb $home/src/9/mtx /sys/src/9/mtx #boot bind -cb $home/src/boot/alphapc /sys/src/boot/alphapc bind -cb $home/src/boot/arm /sys/src/boot/arm bind -cb $home/src/boot/pc /sys/src/boot/pc #fs bind -cb $home/src/fs/port /sys/src/fs/port bind -cb $home/src/fs/choline /sys/src/fs/choline bind -cb $home/src/fs/dev /sys/src/fs/dev bind -cb $home/src/fs/emelie /sys/src/fs/emelie bind -cb $home/src/fs/ip /sys/src/fs/ip bind -cb $home/src/fs/pc /sys/src/fs/pc bind -cb $home/src/fs/roro /sys/src/fs/roro bind -cb $home/src/fs/sony /sys/src/fs/sony #cmd bind -cb $home/src/cmd /sys/src/cmd p9%
Часть #cmd не обязательна, но все равно пусть она там будет
Материал, создаваемый командами Plan 9…
p9% cat /usr/andrey/bin/rc/lbbind #!/bin/rc # материал linuxbios # 9 bind -cb $home/src/linuxbios/pc /sys/src/9/pc bind -cb $home/src/linuxbios/ip /sys/src/9/ip bind -cb $home/src/linuxbios/alphapc /sys/src/9/alphapc bind -cb $home/src/linuxbios/bitsy /sys/src/9/bitsy bind -cb $home/src/linuxbios/boot /sys/src/9/boot bind -cb $home/src/linuxbios/port /sys/src/9/port bind -cb $home/src/linuxbios/mtx /sys/src/9/mtx #boot bind -cb $home/src/boot/alphapc /sys/src/boot/alphapc bind -cb $home/src/boot/arm /sys/src/boot/arm bind -cb $home/src/boot/pc /sys/src/boot/pc #fs bind -cb $home/src/fs/port /sys/src/fs/port bind -cb $home/src/fs/choline /sys/src/fs/choline bind -cb $home/src/fs/dev /sys/src/fs/dev bind -cb $home/src/fs/emelie /sys/src/fs/emelie bind -cb $home/src/fs/ip /sys/src/fs/ip bind -cb $home/src/fs/pc /sys/src/fs/pc bind -cb $home/src/fs/roro /sys/src/fs/roro bind -cb $home/src/fs/sony /sys/src/fs/sony #cmd bind -cb $home/src/cmd /sys/src/cmd p9%
Реально нам нужна лишь команда lbbind, она связывает все исходные тексты в одном дереве.
Пример типичного сеанса Plan 9:
p9% lbbind p9% cd /sys/src/9/pc # редактирование файлов, внесение изменений, и т.п... # сборка ядра cpu p9% mk 'CONF=pccpu' 8c -FVw ether79c970.c 8c -FVw vgabt485.c # здесь происходит компиляция большого количества файлов, могут появляться ошибки # # итак, теперь у вас есть скромное ядро, скопируйте его куда-нибудь, откуда его можно будет загружать p9% cp 9pccpu # этап очистки - не обязательно, но иногда очень забавно :) p9% mk clean rm -f *.v4586xq7 *.root.s cfs.h fs.h init.h conf.h *.out for(i in pc pccpu pcdisk) mk $i.clean rm -f pc.c 9bzpc 9bzpc.gz bootpc.* rm -f pccpu.c 9bzpccpu 9bzpccpu.gz bootpccpu.* rm -f pcdisk.c 9bzpcdisk 9bzpcdisk.gz bootpcdisk.* p9% # для завершения сеанса разработки удалите окно терминала # ваши файлы будут сохранены там :)
Linux
Здесь обратимся за помощью к Рону! Обновление CVS из дистрибутива freebios, затем разархивирование включаемого файла mkelf.tgz, далее зовем Рона, чтобы сделать LinuxBIOS подходящим для объединения с 9loadlb… Я совершенно ничего не знаю об этом процессе. Мне остается лишь отрешенно сидеть перед экраном как цыпленок пока Рон работает… После настройки остается лишь использовать сценарий mymk как показано выше и наслаждаться результатом работы :)
2. Diff-файлы исходного кода с комментариями:
/sys/src/boot/pc/mkfile — файл был изменен для соответствия моим привычкам Plan 9. Добавлена новая цель, а именно ядро 9loadlb linuxbios. Различие в том, что код linuxbios есть #ifdef-ed LinuxBios:
p9% diff boot/pc/mkfile /sys/src/boot/pc/mkfile 7d6 < 9loadlb\ 95,98d93 < 9loadlb: ll.$O $CORE $LOAD $ETHER < $LD -o $target -H3 -T0x80800000 -l $prereq -lflate -lc < ls -l $target < 118,120d112 < < ll.$O: l.s < $AS -DLinuxBios -o ll.$O l.s p9%
/sys/src/boot/pc/l.s — код режима реального времени, 9load загружается в защищенном режиме. Код добавлен для загрузки GDT. Несколько попыток для устранения проблемы с маршрутизацией IRQ, но ничего широко не тестировалось. Мы давным-давно закончили погоню за ошибкой посредством:
MOV AX, SS
теперь ошибка никогда не появляется при нормальной загрузке BIOS…
Материал
MOVL $0x80, DX MOVB $0x19, AL OUTB
diff:
p9% diff boot/pc/l.s /sys/src/boot/pc/l.s 20,24d19 < < MOVL $0x80, DX < MOVB $0x11, AL < OUTB < 27c22 < #ifndef LinuxBios --- > 200,202d194 < < < 209c201 < MOVL $1,AX --- > LWI(1, rAX) 213,216d204 < /* MOVL CR0,AX < ORL $1,AX < MOVL AX,CR0 < */ 227,238c215,218 < < #endif /* LinuxBios */ < < < MOVL $0x80, DX < MOVB $0x11, AL < OUTB < < MOVL tgdtptr-KZERO(SB),GDTR /**/ < < < MOVW $SELECTOR(1, SELGDT, 0),AX /**/ --- > /* MOVW $SELECTOR(1, SELGDT, 0),AX /**/ > BYTE $0xc7 > BYTE $0xc0 > WORD $SELECTOR(1, SELGDT, 0) 239a220 > MOVW AX,SS 243d223 < MOVW AX,SS 245,249d224 < MOVL $0x80, DX < MOVB $0x12, AL < OUTB < < #ifndef LinuxBios 255,256c230,231 < #endif /* linuxbios */ < TEXT mode32bit(SB),$0 --- > > TEXT mode32bit(SB),$0 266,270d240 < < MOVL $0x80, DX < MOVB $0x13, AL < OUTB < 274,277d243 < MOVL $0x80, DX < MOVB $0x14, AL < OUTB < 290,292d255 < < < 308d270 < 320d281 < 345,348d305 < MOVL $0x80, DX < MOVB $0x17, AL < OUTB < 361,363d317 < MOVL $0x80, DX < MOVB $0x18, AL < OUTB 371,374d324 < < MOVL $0x80, DX < MOVB $0x19, AL < OUTB p9%
/sys/src/boot/pc/ether.c — модифицирован для апробации ethernet карт без их конфигурирования в plan9.ini (здесь не используется plan9.ini). Все найденные устройства ether получают irq 9.
p9% diff boot/pc/ether.c /sys/src/boot/pc/ether.c 41d40 < 62,63c61,62 < // if(isaconfig("ether", ctlrno, ctlr) == 0) < // continue; --- > if(isaconfig("ether", ctlrno, ctlr) == 0) > continue; 66,67d64 < memset(ctlr, 0, sizeof(Ether)); < strcpy(ctlr->type, ethercardsn.type); 73,74c70 < i = (*ethercardsn.reset)(ctlr); < if(i < 0) { --- > if((*ethercardsn.reset)(ctlr)){ 76,78d71 < continue; < } else if(i) { < splx(x); 86d78 < //ctlr->irq = 9; p9%
/sys/src/boot/pc/load.c — переделан для загрузки вне ether0 после завершения поиска и конфигурирования устройств pci и жестких дисков. Если bootp ether0 терпит неудачу (например, дано плохое ядро) load.c запрашивает другое устройство загрузки. Проверка «я слишком большой» закомментирована. Поддержка консоли аппаратная (нет plan9.ini для ее включения). Инициализация console() идет одной из первых — просто я желаю столько вывода отладки, сколько это возможно!
p9% diff boot/pc/load.c /sys/src/boot/pc/load.c 125d124 < 149,162d147 < static int < myboot(char* file) < { < char *eth = "ether0"; < Type *tp; < Medium *mp; < < for(tp = types; tp->type != Tnil; tp++) < for(mp = tp->media; mp; mp = mp->next) < if(strcmp(mp->name, eth) == 0) < boot(mp, file); < < } < 252,254d236 < delay(100000); < < outb(0x80, 0x20); 256d237 < outb(0x80, 0x21); 258,264d238 < outb(0x80, 0x22); < < outb(0x80, 0x27); < consinit("0", "115200"); < outb(0x80, 0x28); < kbdinit(); < 266d239 < outb(0x80, 0x23); 268d240 < outb(0x80, 0x24); 270d241 < outb(0x80, 0x25); 272d242 < outb(0x80, 0x26); 274,277c244 < outb(0x80, 0x27); < // consinit("0", "115200"); < outb(0x80, 0x28); < // kbdinit(); --- > kbdinit(); 279,283c246,247 < print("hi!\n"); < pcihinv(nil); < outb(0x80, 0x29); < // if((ulong)&end > (KZERO|(640*1024))) < // panic("я слишком большой\n"); --- > if((ulong)&end > (KZERO|(640*1024))) > panic("я слишком большой\n"); 285d248 < outb(0x80, 0x30); 287d249 < outb(0x80, 0x31); 297d258 < outb(0x80, 0x32); 299d259 < outb(0x80, 0x33); 301,304c261,262 < // if((p = getconf("console")) != nil) < // consinit(p, getconf("baud")); < < outb(0x80, 0x34); --- > if((p = getconf("console")) != nil) > consinit(p, getconf("baud")); 306d263 < outb(0x80, 0x35); 308d264 < outb(0x80, 0x36); 318d273 < outb(0x80, 0x37); 322d276 < outb(0x80, 0x38); 337d290 < outb(0x80, 0x39); 365,368d317 < outb(0x80, 0x40); < myboot(file); /* переделанная загрузка ether0 */ < outb(0x80, 0x41); < 443a393,395 > extern void diff(char*); > > ulong palloc; 447,448d398 < < static ulong palloc; 464d413 < p9%
Все остальное вы найдете в каталоге, основная часть моих попыток относится к решению проблемы с прерываниями в эмуляторе 8259 (trap.c), вы безболезненно можете удалить эти файлы.
Изменения в ядре Plan 9
Конфигурационные файлы существенно упрощены — я стремился к уменьшению драйверов насколько это было возможно. У меня получилось ядро в 365 KB, упрощенное и компрессированное…
/sys/src/9/pc/main.c — просто море информации для отладки.
В main() я хотел сделать так, чтобы при возникновении аварийной ситуации я знал что и где полетело… Также была добавлена некоторая отладочная информация о pci (pcihinv() выводит устройства pci).
p9% diff linuxbios/pc/main.c /sys/src/9/pc/main.c 76d75 < outb(0x80, 0xA0); 78d76 < outb(0x80, 0xA0); 80d77 < outb(0x80, 0xA1); 82,83d78 < outb(0x80, 0xA2); < kbdinit(); 85d79 < outb(0x80, 0xA3); 88d81 < outb(0x80, 0xA4); 91c84 < outb(0x80, 0xA6); --- > kbdinit(); 93d85 < outb(0x80, 0xA7); 95d86 < outb(0x80, 0xA8); 97d87 < outb(0x80, 0xA9); 99d88 < outb(0x80, 0xAa); 101d89 < outb(0x80, 0xAb); 103d90 < outb(0x80, 0xAc); 105d91 < outb(0x80, 0xAd); 107d92 < outb(0x80, 0xAe); 109d93 < outb(0x80, 0xAf); 111d94 < outb(0x80, 0xb0); 113d95 < outb(0x80, 0xb1); 116d97 < outb(0x80, 0xb2); 118d98 < outb(0x80, 0xb3); 120d99 < outb(0x80, 0xb4
Copyright © 2003 Перевод Андрей С. Кухар. Последняя модификация 27.08.2003