Как Linux использует преобразование адресов на РРС

Мы знаем, как выглядит код, выполняющий управление памятью на РРС.
Следующий код является первым, получающим управления в ядре. Эта функция выполняет обратный вызов Firmware для выделения временной области с помощью функции claim (). Далее ядро распаковывается в соответствующее место.
Управляющие биты
Биты W, I, М, G, R и С управляют доступом процессора к кешу и основной памяти:
• W (Write Thought, повсеместная запись). Если данные находятся в кеше и над ними производится операция сохранения, при W=l копия в памяти также обновляется.
• I (Cache Ingibit, запрет кеша). Обновление минует кеш и обращается к основной памяти напрямую.
• М (Memory Coherence, согласование памяти). При W=l выполняется принудительно-аппаратное согласование памяти.
• G (Guarded, безопасность). При G=l конкурентное выполнение запрещено.
• R (Referenced, ссылка). При R=l считаются ссылки на вхождения таблицы страниц.
• С (Changed, изменение). При С=1 вхождения таблицы страниц изменяются.

55 printf("initial ramdisk moving Ox%x <- Ox%p (%x bytes)\n\r",
56 initrd_start, (char *) (& ramdisk_begin), initrd_size)
57 memcpyl(char *)initrd_start, (char *)(& ramdisk_begin),
initrd_size);

63 /* выделение ЗМВ начиная с PROG_START */
64 claim(PROG_START, PROG_SIZE, 0);
65 dst = (void *) PROG_START;
66 if (im[0] == Oxlf && im[l] == 0x8b) {
dst, im, im+len)
67 /* выделение памяти для временного рабочего пространства */
68 avail_ram = (char *) claim(0, SCRATCH_SIZE, 0x10);
69 begin_avail = avail_high = avail_ram;
70 end_avail = avail_ram + SCRATCH_SIZE;
71 printf("heap at 0x%p\n", avail_ram);
72 printf("gunzipping (0x%p <- 0x%p:0x%p)..
73 gunzipfdst, PROG_SIZE, im, &len);
74 printf("done %u bytes\n", len);
75 printf("%u bytes of heap consumed, max in use %u\n", 7 6 avail_high - begin_avail, heap_max),-
86 87 88 89

sa = (unsigned long)PROG_START;
printf("start address = 0x%x\n", sa);
(*(kernel_start_t)sa)(al, a2, prom);

Строка 54
Функция claim () вызывается для выделения памяти сразу за 1 Мб и копирования диска в памяти (ramdisk) в эту память.
Строка 64
Функция claim () вызывается для выделения 3 Мб начиная с 0х1_0000 для образа. Строка 68
Функция claim () вызывается для выделения 8 Кб памяти начиная с 0x00 для временной кучи.
Строка 73
Образ распаковывается в адрес 0xl_0000 (PROG_START). Строка 89
Переход на 0x1 0000 [ (*kernel_start_t) sa] с параметрами (al, а2 и prom), где al хранит значение в гЗ (равное загрузочному ramdisc start), а2 хранит значение в г4 (равное размеру загрузочного диска или Oxdeadbeef в случае по ramdisk) и prom хранит значение в г5 (код хранится в системной памяти).
Следующий блок кода подготавливает аппаратные особенности управления памятью для различных процессоров PowerPC. Первые 16 Мб памяти отображаются в 0x0000000:

arch/ppc/kernel/head.S
131 start:
150 Ы early_init in (283)
170 Ы mmu_off
171 RFI: SRR0=>IP, SRR1=>MSR
172 tifndef CONFIG_POWER4
173 Ы clear_bats
174 Ы flush_tlbs 175
176 bl initial_bats
177 #if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT)
178 Ы setup_disp_bat
179 #endif
180 #else /* CONFIG_POWER4 */

181 bl reloc_offset
182 bl initial_mra_power4
183 #endif /* CONFIG_POWER4 */
Строка 131
Это точка входа в код. Получает установленное mnu окружение. (Обратите внимание, что APUS расшифровывается как Amiga Power Up System.)
Строка 150
Адрес, куда распаковывается ядро, и с чем оно связывается могут отличаться. Функция early_in.it возвращает физический адрес текущего кода.
Строка 170
Отключение модуля управления памятью на РРС. Если включены ГО. и DR, он остается включенным; в противном случае переразмещение отключено.
Строки 173-176
Если процессор не является процессором power4 или G5, то регистры ВАТ очищаются, сбрасываются TLB, а ВАТ настраивается для отображения первых 16 Мб памяти в ОхсООООООО.
Обратите внимание, как внутри ядра используются различные метки для памяти
ядра.

arch/ppc/defconfig CONFIG_KERNEL_START=0xc0 0 00000

И

include/asm-ppc/page.h
tdefine PAGE_OFFSET CONFIG_KERNEL_START
#define KERNELBASE PAGE_OFFSET

Строки 181-182
При использовании сегментации настраивается память ядра для power4 и G5. Строки 188-198
setup_cpu () инициализирует особенности ядра и использования, такие, как настройка кеша и наличие FPU и MMU. (Примите во внимание, что на момент написания книги init_idle_power4 ничего не выполняет.)
Строка 210
Перевыделение ядра в KERNELBASE или 0x00 в зависимости от платформы. Строки 224-232
Включение MMU (если он еще не включен) с помощью включения ГО и DR в MSR. Далее выполняется инструкция RFI, производящая переход к метке start_here:. (Внимание: инструкция RFI загружает в MSR содержимое SRR1 и переходит к SRR0.)
Далее стартует следующий код. Он настраивает всю память системы на основе строки команд:

arch/ppc/kernel/head.S
1337 start here:

1364 Ы
1365 Ы

machine_ini t MMU init

1385 lis r4,2f@h
1386 ori r4,r4,2f@l
1387 tophys(r4,r4)
1388 li r3,MSR_KERNEL &

•(MSR_IR|MSR_DR)

1389 1390 1391 1392 1393 1394 1395

FIX_SRR1(r3,г5)
mtspr SRR0,r4
mtspr SRR1,r3
SYNC RFI
/* Загрузка контекста ядра */
2: Ы load_up_mmu

1411 1412 1413 1414 1415 1416 1417

/* Now turn on the MMU for real! */
li r4,MSR_KERNEL
FIX_SRRl(r4,r5)
lis r3,start_kernel@h
ori r3,r3,start_kernel@l
mtspr SRRO,r3
mtspr SRRl,r4

1418 SYNC
1419 RFI

Строка 1337
Это строка является точкой входа для этого кода.
Строка 1364
machine_init () (см. файл arch/ppc/kernel. setup. с, строка 532) настраивает машинно-зависимую информацию, такую, как NVRAM, L2, количество линий кеша CPU, отладка и т. д.
Строка 1365
MMU_init() (см. файл arch/ppc/mm/init. с, строка 234) определяет общий размер для highmem и lowmem. Далее она инициализирует аппаратный MMU (MMU_init_hw(), строка 267), настраивает таблицу хеша страниц (arch/ppc/ mm/hashtable. s), отображает всю память в KERNELBASE (mapin_ram (), строка 272), отображает весь ввод-вывод (setup_io_mapping(), строка 285) и инициализирует управление контекстом (mmu_context_init (), строка 288).
Строка 1385
Отключение IR и DR для включения SDR1. Хранит реальный адрес таблицы страниц и то, сколько битов из хеша используется в индексе таблицы страниц.
Строка 1395
Очистка TLB, загрузка SDR1 (основа хеша таблиц и размер), устанавливает сегментацию и в зависимости от конкретной платформы РРС инициализирует регистры
ВАТ.

420

Глава 8 • Загрузка ядра

Строки 1412-1419
Включение ГО., DR и RFI для start_kernel в /init/main.c. Обратите внимание, что в момент прерывания на архитектуре PowerPC содержимое Instruction Address Register (ISR)1 хранит адреса, которые должен возвращать процессор после обслуживания прерывания. Это значение сохраняется в Save Restore Register 0 (SRR0) . Регистр состояния машины, в свою очередь, сохраняется в Save Restore Register 1 (SRR1). Коротко говоря, во время прерывания:
• IAR->SRR0
• MSR->SRR1
Инструкция RFI, которая обычно выполняется в конце функции прерывания, является обратной процедурой, когда SRR0 восстанавливается в IAR и SRR1 восстанавливается в MSR. Коротко говоря:
• SRR0->IAR
• SRR1->MSR
Код в строках 1385-1419 использует эту методику для включения управления памятью и выключения за три шага:
1. Установка желаемого бита для MSR (в соответствии с рис. 8.1) в SRR1.
2. Запись желаемого адреса, куда мы хотим перейти в SRR0.
3. Выполнение инструкции RFI.