Доброго времни суток! В книжках и статьях весьма неплохо описан процесс начальной загрузки компьютера. С выгрузкой (?) все не так прозрачно, во всяком случае я не видела ничего похожего на описание кода, выключающего компьютер.... Подскажите пожалуйста, где можно узнать про то, как завершить работу системы на аппаратном уровне, работая в защищенном режиме процессора? Т.е. желательно без прерываний BIOS. А то я тут загрузчик пишу, а выключаться кнопкой что-т не смешно... Благодарю за внимание!
T_A_M_A_R_A Читаем спецификацию Advanced Power Management (APM). Там есть точки для выключения как в реальном так и в защищенном режиме. Code (Text): POWER_OFF: mov ax, 0x5301 xor bx, bx int 0x15 mov ax, 0x5308 mov bx, 1 mov cx, bx int 0x15 mov ax, 0x530D mov bx, 1 mov cx, bx int 0x15 mov ax, 0x530F mov bx, 1 mov cx, bx int 0x15 mov ax, 0x530E xor bx, bx mov cx, 0x102 int 15h mov ax, 0x5307 mov bx, 1 mov cx, 3 int 0x15 jmp $
T_A_M_A_R_A Это будет нелегко... С БИОСом, как показал Pavia все более-менее стандартно, а вот напрямую - тут у каждого чипсета свои заморочки. Один мой коллега что-то ковырял, но только по Intel'овским чипам, и то ругался, что они шибко разные... На i915 у него вроде получалось выключить питание одной записью в порт. Причем эту святую комбинацию он выковырял методом исследования обработчика все того же int 15.
вообщем-то ничего особо страшного в выключении через ACPI и нет. Главная тонкость в получении значения SLP_TYP, соответствующего Soft Off. По "правильному" его надо получать из AML -- а именно, от объекта _S5, т.е. как бы само собой подразумевается наличие тяжеловесного AML-интерпретатора даже для такой простой задачи. Всю остальную инфу можно почерпнуть из таблиц в чистом виде. Но можно задействовать и читерский "правильный" способ, который опирается на тот факт, что _S5 (и вообще _Sx) реализован в виде dword'ового Package'а, который можно тупо найти в DSDT по сигнатуре, без парсинга AML, и взять значение для S5 напрямую. Есть еще один, расп..ский, способ -- взять фиксированные значения SLP_TYP вместо возни с AML-кодом. Во всех наблюдаемых чипсетах SLP_TYP для S5 равен либо 111b (7) -- чипсеты Intel, AMD, nvidia, либо 010b (2) -- чипсеты VIA. Что замечательно, это то, что у первых 010b попадает в резервед, а у вторых -- 111b в резерведе. Налицо масонский заговор, hehe. Есть конечно некоторые, у которых S5 SLP_TYP не 2 и не 7, но они составляют позорное меньшинство (устаревшее). Вот пример того самого читерского "правильного" способа -- получение S5 SLP_TYP непосредственно из DSDT, но без парсинга AML. Из функций ядра используется только работа с физ.маппингом. Особо его не тестил на разных машинах, но по-хорошему надо потестить, т.к. по идее должен работать не только у меня, а в идеале универсально на всех тачках с ACPI. Перед тестом лучше перезагрузиться, чтобы хоть отчасти уменьшить вероятность потери каких-либо архиважных данных из-за внезапного отрубания питания. Поддержка APM постепенно сходит на нет, так что на ACPI все равно придется переходить, благо afaik он приживется и под EFI. Code (Text): ;------------------------------------------------------------------ ; Turn off PC via ACPI soft off ;------------------------------------------------------------------ pushad mov word ptr [PM1a_CNT_SLP_S5], -1 ; first, map bios' F segment _call MmMapIoSpace, 0F0000h, 0, 64 K, 0 push eax ; now search RSDP struc mov ecx, 64 K - 8 @@srch_rsdp: cmp dword ptr [eax], ' DSR' ; scan for "RSD PTR " jnz @@rsdp_next cmp dword ptr [eax+4], ' RTP' jz @@fnd_rsdp @@rsdp_next: inc eax loop @@srch_rsdp jmp @@done ; RSDP signature not found @@fnd_rsdp: _call MmMapIoSpace, dword ptr [eax+10h], 0, 36, 0 push eax xchg eax, esi ; esi --> RSDT lodsd cmp eax, 'TDSR' jnz @@rsdt_done lodsd sub eax, 36 add esi, 36 - 8 shr eax, 2 ; eax = number of RSDT entries xchg eax, edi @@l_rsdt: lodsd _call MmMapIoSpace, eax, 0, 60h, 0 ; should be enough push eax xchg eax, ebx cmp dword ptr [ebx], 'PCAF' jnz @@entry_done ; ebx --> FADT, get ACPI I/O ranges mov eax, [ebx+38h] mov [PM1a_EVT_BLK], eax mov eax, [ebx+3Ch] mov [PM1b_EVT_BLK], eax mov eax, [ebx+40h] mov [PM1a_CNT_BLK], eax mov eax, [ebx+44h] mov [PM1b_CNT_BLK], eax movzx eax, byte ptr [ebx+58h] mov [PM1_EVT_LEN], eax movzx eax, byte ptr [ebx+59h] mov [PM1_CNT_LEN], eax mov ebx, [ebx+28h] ; ebx = DSDT phys addr ; get full mapping len _call MmMapIoSpace, ebx, 0, 8, 0 mov edi, dword ptr [eax+4] ; edi = DSDT length in bytes _call MmUnmapIoSpace, eax, 8 ; now map the whole DSDT range _call MmMapIoSpace, ebx, 0, edi, 0 push edi push eax xchg eax, edx ; edx --> DSDT data, edi = DSDT length, scan for _S5 object sub edi, 8 @@l_srch_s5: cmp dword ptr [edx], '_5S_' jnz @@s5_next cmp byte ptr [edx+4], 12h jnz @@s5_next mov al, [edx+8] mov [PM1a_CNT_SLP_S5], al mov al, [edx+0Ah] mov [PM1b_CNT_SLP_S5], al jmp short @@s5_done @@s5_next: inc edx dec edi jnz @@l_srch_s5 @@s5_done: pop eax pop edi _call MmUnmapIoSpace, eax, edi ; unmap DSDT push 1 pop edi ; break @@entry_done: pop eax _call MmUnmapIoSpace, eax, 60h dec edi jnz @@l_rsdt @@rsdt_done: pop eax _call MmUnmapIoSpace, eax, 36 @@done: ; unmap F segment pop eax _call MmUnmapIoSpace, eax, 64 K ; phew! no more f**king mappings cmp word ptr [PM1a_CNT_SLP_S5], -1 jz @@done_off ; probably system doesn't support Soft Off ; do the actual transition to the S5 state mov ebx, [PM1_EVT_LEN] shr ebx, 1 xor eax, eax mov edx, [PM1a_EVT_BLK] test edx, edx jz @@done_pm1a_evt add edx, ebx ; edx = _EN-register I/O address cmp ebx, 2 jnz @@not_2 out dx, ax jmp short @@done_pm1a_evt @@not_2: out dx, eax @@done_pm1a_evt: mov edx, [PM1b_EVT_BLK] test edx, edx jz @@done_pm1b_evt add edx, ebx ; edx = _EN-register I/O address cmp ebx, 2 jnz @@not_2_ out dx, ax jmp short @@done_pm1b_evt @@not_2_: out dx, eax @@done_pm1b_evt: ; first, write to PM1a_CNT.SLP_TYP, then to PM1b_CNT.SLP_TYP movzx eax, byte ptr [PM1a_CNT_SLP_S5] shl eax, 10 ; move it to SLP_TYPx position bts eax, 13 ; set SLP_EN mov edx, [PM1a_CNT_BLK] test edx, edx jz @@done_pm1a_cnt out dx, ax ; compatible with both 16 and 32 bits @@done_pm1a_cnt: movzx eax, byte ptr [PM1b_CNT_SLP_S5] shl eax, 10 ; move it to SLP_TYPx position bts eax, 13 ; set SLP_EN mov edx, [PM1b_CNT_BLK] test edx, edx jz @@done_pm1b_cnt out dx, ax ; compatible with both 16 and 32 bits @@done_pm1b_cnt: ; There is only one reason to get here -- if all the above crap didn't work @@done_off: popad P.S. Это кстати и есть выключение "напрямую", т.е. через порты, с той лишь разницей что информация, в какие порты и что писать, берется от ACPI, а не от идентификации чипсетов и индивидуальной работы с ними.
_BC_ в доступных мне сорцах коды для State5 искались как раз через доступ к объекту _S5. со всеми вытекающими =)
n0name да, но надо полагать, не без помощи громоздкого AML-интерпретатора? Здесь же практически никакой работы с AML. add: кто-нть у себя пробовал запускать?
Вообще, _BC_, как всегда, на высоте. Правда, я лично банально привязываюсь к чипсетам. Благо их нонче совсем не так уж и много. В результате, например, для Intel получится "чуть" короче: Code (Text): mov dx, 404h in ax, dx out 0EBh, al mov ah, 111100b out dx, ax
apple_rom только еще надо тогда добавить взятие PMBASE из pci conf'а, вместо постоянной базы, она к счастью на всех интелах кроме древнейших PIIX'ов берется одинаково, c B031:F0:40h.
В том то и дело, что всё к тому же самому счастью, почти всегда она (PMBASE) равна 400. п.с. Однако, повторюсь, что в случае написания "универсальной" утилиты - правильней "вычислять" всё "ручками". В частности, вычитывая нужное из PCI-регистров для Power Management.
Всем привет! Помогите разобраться, не могу добраться до таблиц ACPI :/ Под виндой приведеный _BC_ пример работает великолепно. Работаю в защищенном режиме. Читаю в запись "RSD PTR" в биос Code (Text): 000FA160 52 53 44 20 50 54 52 20 6C 41 4D 49 20 20 20 00 RSD PTR lAMI . 000FA170 00 00 FF 3F C0 6E 06 00 E9 B4 E1 2E F6 06 C1 E2 ...?.n.......... Size: 20 ACPI detected at: 000FA160 , RsdtAddress: 3FFF0000 , Revision: 0, oem: AMI , Checksum: 108 По полученному адрессу находится какая то фигня: Code (Text): 3FFF0000 67 00 00 03 67 10 00 03 67 20 00 03 67 30 00 03 g...g...g ..g0.. 3FFF0010 67 40 00 03 67 50 00 03 67 60 00 03 67 70 00 03 g@..gP..g`..gp.. 3FFF0020 67 80 00 03 67 90 00 03 67 A0 00 03 67 B0 00 03 g...g...g...g... 3FFF0030 67 C0 00 03 67 D0 00 03 67 E0 00 03 67 F0 00 03 g...g...g...g... У меня память адрессуется 1:1 до указанного адресса включительно. Code (Text): {P cpuid= 0, pid= 368 Virtual Physical Size 00001000 00001000 1048568KB---------------------- 3FFFE000h> 3FFF0000H>0 ??? 80001000 3FEFC000 4KB 80002000 3FEFA000 4KB 80003000 DFFFF000 8KB 80005000 C0000000 2MB .... .... .... .... Может кто то что нибудь подскажет? Таблица RSDT копируется в оперативную память? Тогда может что то ее портит? Или нужно делать какие либо манипуляции с RsdtAddress? Вобщем жду любого совета, т.к. зашел в конкретный тупик...
В самом главном коде приведённом _BC_, есть, кажется, ошибочка Code (Text): mov al, [edx+0Ah] mov [PM1b_CNT_SLP_S5], al Должно быть [edx+09h]. По спецификации на каждое поле выделяется по байту
Тема старая... Если речь идет о выборке из пакета \_S5, то нужно знать AML, чтобы понять, что смещение может быть разным. Да, действительно по спецификации данный пакет должен содержать 4 значения размером 1 байт каждое, но во-первых длина пакета может кодироваться 1-4 байтами (для этого пакета достаточно 1 байта, но компилятор может поступить и подругому), а во-вторых каждое значение размером 1 байт может кодироваться 1-2 байтами (если присутствует байт-префикс, то поле имеет размер 2 байта).