Ivan Baravy
de8ecf4c59
The code expects the register is in system_io space. Other options are not implemented but it works on my computer (c). git-svn-id: svn://kolibrios.org@7734 a494cfbc-eb01-0410-851d-a64ba20cac60
408 lines
9.8 KiB
PHP
408 lines
9.8 KiB
PHP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; ;;
|
|
;; Copyright (C) KolibriOS team 2004-2016. All rights reserved. ;;
|
|
;; Distributed under terms of the GNU General Public License ;;
|
|
;; ;;
|
|
;; Shutdown for Menuet ;;
|
|
;; ;;
|
|
;; Distributed under General Public License ;;
|
|
;; See file COPYING for details. ;;
|
|
;; Copyright 2003 Ville Turjanmaa ;;
|
|
;; ;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
$Revision$
|
|
|
|
; ACPI Generic Address Structure
|
|
struct GAS
|
|
asid db ? ; address space id
|
|
bit_width db ?
|
|
bit_offset db ?
|
|
access_size db ?
|
|
address DQ ?
|
|
ends
|
|
|
|
ASID.SYSTEM_MEMORY = 0
|
|
ASID.SYSTEM_IO = 1
|
|
ASID.PCI_CONFIG = 2
|
|
ASID.PCI_EC = 3
|
|
ASID.PCI_SMBUS = 4
|
|
|
|
ACCESS_SIZE.UNDEFINED = 0
|
|
ACCESS_SIZE.BYTE = 1
|
|
ACCESS_SIZE.WORD = 2
|
|
ACCESS_SIZE.DWORD = 3
|
|
ACCESS_SIZE.QWORD = 4
|
|
|
|
align 4
|
|
system_shutdown: ; shut down the system
|
|
|
|
cmp byte [BOOT.shutdown_type], SYSTEM_SHUTDOWN
|
|
jb @F
|
|
cmp byte [BOOT.shutdown_type], SYSTEM_RESTART
|
|
jbe .valid
|
|
@@:
|
|
ret
|
|
.valid:
|
|
call stop_all_services
|
|
|
|
yes_shutdown_param:
|
|
; Shutdown other CPUs, if initialized
|
|
cmp [ap_initialized], 0
|
|
jz .no_shutdown_cpus
|
|
mov edi, [LAPIC_BASE]
|
|
add edi, 300h
|
|
mov esi, smpt+4
|
|
mov ebx, [cpu_count]
|
|
dec ebx
|
|
.shutdown_cpus_loop:
|
|
lodsd
|
|
push esi
|
|
xor esi, esi
|
|
inc esi
|
|
shl eax, 24
|
|
mov [edi+10h], eax
|
|
; assert INIT IPI
|
|
mov dword [edi], 0C500h
|
|
call delay_ms
|
|
@@:
|
|
test dword [edi], 1000h
|
|
jnz @b
|
|
; deassert INIT IPI
|
|
mov dword [edi], 8500h
|
|
call delay_ms
|
|
@@:
|
|
test dword [edi], 1000h
|
|
jnz @b
|
|
; don't send STARTUP IPI: let other CPUs be in wait-for-startup state
|
|
pop esi
|
|
dec ebx
|
|
jnz .shutdown_cpus_loop
|
|
.no_shutdown_cpus:
|
|
|
|
cli
|
|
call IRQ_mask_all
|
|
|
|
mov eax, dword[BOOT.shutdown_type]
|
|
cmp al, SYSTEM_RESTART
|
|
jne @F
|
|
|
|
; load kernel.mnt to _CLEAN_ZONE
|
|
mov ebx, kernel_file_load
|
|
pushad
|
|
call file_system_lfn
|
|
popad
|
|
@@:
|
|
mov esi, OS_BASE+restart_code_start ; move kernel re-starter to 0x5000:0
|
|
mov edi, OS_BASE+0x50000
|
|
mov ecx, (restart_code_end - restart_code_start)/4
|
|
rep movsd
|
|
|
|
call create_trampoline_pgmap
|
|
mov cr3, eax
|
|
jmp @F
|
|
org $-OS_BASE
|
|
@@:
|
|
|
|
;disable paging
|
|
|
|
mov eax, cr0
|
|
and eax, 0x7FFFFFFF
|
|
mov cr0, eax
|
|
mov eax, cr3
|
|
mov cr3, eax
|
|
|
|
cmp byte [BOOT_LO.shutdown_type], SYSTEM_SHUTDOWN
|
|
jne no_acpi_power_off
|
|
|
|
; system_power_off
|
|
|
|
mov ebx, [acpi_fadt_base-OS_BASE]
|
|
cmp dword [ebx], 'FACP'
|
|
jne no_acpi_power_off
|
|
mov esi, [acpi_dsdt_base-OS_BASE]
|
|
cmp dword [esi], 'DSDT'
|
|
jne no_acpi_power_off
|
|
mov eax, [esi+4] ; DSDT length
|
|
sub eax, 36+4
|
|
jbe no_acpi_power_off
|
|
add esi, 36
|
|
.scan_dsdt:
|
|
cmp dword [esi], '_S5_'
|
|
jnz .scan_dsdt_cont
|
|
cmp byte [esi+4], 12h ; DefPackage opcode
|
|
jnz .scan_dsdt_cont
|
|
mov dl, [esi+6]
|
|
cmp dl, 4 ; _S5_ package must contain 4 bytes
|
|
; ...in theory; in practice, VirtualBox has 2 bytes
|
|
ja .scan_dsdt_cont
|
|
cmp dl, 1
|
|
jb .scan_dsdt_cont
|
|
lea esi, [esi+7]
|
|
xor ecx, ecx
|
|
cmp byte [esi], 0 ; 0 means zero byte, 0Ah xx means byte xx
|
|
jz @f
|
|
cmp byte [esi], 0xA
|
|
jnz no_acpi_power_off
|
|
inc esi
|
|
mov cl, [esi]
|
|
@@:
|
|
inc esi
|
|
cmp dl, 2
|
|
jb @f
|
|
cmp byte [esi], 0
|
|
jz @f
|
|
cmp byte [esi], 0xA
|
|
jnz no_acpi_power_off
|
|
inc esi
|
|
mov ch, [esi]
|
|
@@:
|
|
jmp do_acpi_power_off
|
|
.scan_dsdt_cont:
|
|
inc esi
|
|
dec eax
|
|
jnz .scan_dsdt
|
|
jmp no_acpi_power_off
|
|
do_acpi_power_off:
|
|
mov edx, [ebx+48]
|
|
test edx, edx
|
|
jz .nosmi
|
|
mov al, [ebx+52]
|
|
out dx, al
|
|
mov edx, [ebx+64]
|
|
@@:
|
|
in ax, dx
|
|
test al, 1
|
|
jz @b
|
|
.nosmi:
|
|
and cx, 0x0707
|
|
shl cx, 2
|
|
or cx, 0x2020
|
|
mov edx, [ebx+64]
|
|
in ax, dx
|
|
and ax, 203h
|
|
or ah, cl
|
|
out dx, ax
|
|
mov edx, [ebx+68]
|
|
test edx, edx
|
|
jz @f
|
|
in ax, dx
|
|
and ax, 203h
|
|
or ah, ch
|
|
out dx, ax
|
|
@@:
|
|
jmp $
|
|
|
|
no_acpi_power_off:
|
|
cmp byte[BOOT_LO.shutdown_type], SYSTEM_REBOOT
|
|
jnz no_acpi_reboot
|
|
; try to reboot via ACPI fixed features
|
|
mov ebx, [acpi_fadt_base-OS_BASE]
|
|
cmp dword[ebx], 'FACP'
|
|
jne no_acpi_power_off
|
|
test dword[ebx+0x70], 1 SHL 10 ; RESET_REG_SUP
|
|
jz no_acpi_reboot
|
|
cmp [ebx+0x74+GAS.asid], ASID.SYSTEM_IO
|
|
jnz no_acpi_reboot
|
|
cmp [ebx+0x74+GAS.bit_width], 8
|
|
jnz no_acpi_reboot
|
|
cmp [ebx+0x74+GAS.bit_offset], 0
|
|
jnz no_acpi_reboot
|
|
cmp [ebx+0x74+GAS.access_size], ACCESS_SIZE.BYTE
|
|
ja no_acpi_reboot
|
|
cmp [ebx+0x74+GAS.address.hi], 0
|
|
jnz no_acpi_reboot
|
|
mov edx, [ebx+0x74+GAS.address.lo]
|
|
movzx eax, byte[ebx+0x80]
|
|
out dx, al
|
|
jmp $
|
|
; unreachable
|
|
no_acpi_reboot:
|
|
jmp 0x50000
|
|
|
|
align 4
|
|
restart_code_start:
|
|
org 0x50000
|
|
|
|
cmp byte [BOOT_LO.shutdown_type], SYSTEM_RESTART
|
|
jne @F
|
|
|
|
mov esi, _CLEAN_ZONE-OS_BASE
|
|
mov edi, 0x10000
|
|
mov ecx, 0x31000/4
|
|
cld
|
|
rep movsd
|
|
@@:
|
|
|
|
xor ebx, ebx
|
|
xor edx, edx
|
|
xor ecx, ecx
|
|
xor esi, esi
|
|
xor edi, edi
|
|
xor ebp, ebp
|
|
lidt [.idt]
|
|
lgdt [.gdt]
|
|
jmp 8:@f
|
|
align 8
|
|
.gdt:
|
|
; selector 0 - not used
|
|
dw 23
|
|
dd .gdt
|
|
dw 0
|
|
; selector 8 - code from 5000:0000 to 1000:FFFF
|
|
dw 0FFFFh
|
|
dw 0
|
|
db 5
|
|
db 10011011b
|
|
db 00000000b
|
|
db 0
|
|
; selector 10h - data from 1000:0000 to 1000:FFFF
|
|
dw 0FFFFh
|
|
dw 0
|
|
db 1
|
|
db 10010011b
|
|
db 00000000b
|
|
db 0
|
|
.idt:
|
|
dw 256*4
|
|
dd 0
|
|
org $ - 0x50000
|
|
use16
|
|
@@:
|
|
mov ax, 10h
|
|
mov ds, ax
|
|
mov es, ax
|
|
mov fs, ax
|
|
mov gs, ax
|
|
mov ss, ax
|
|
|
|
mov eax, cr0
|
|
and eax, not 80000001h
|
|
mov cr0, eax
|
|
jmp 0x5000:.real_mode
|
|
|
|
align 4
|
|
.real_mode:
|
|
|
|
; setup stack
|
|
|
|
mov ax, (TMP_STACK_TOP and 0xF0000) shr 4
|
|
mov ss, ax
|
|
mov esp, TMP_STACK_TOP and 0xFFFF
|
|
|
|
;remap IRQs
|
|
mov al, 0x11
|
|
out 0x20, al
|
|
out 0xA0, al
|
|
|
|
mov al, 0x08
|
|
out 0x21, al
|
|
mov al, 0x70
|
|
out 0xA1, al
|
|
|
|
mov al, 0x04
|
|
out 0x21, al
|
|
mov al, 0x02
|
|
out 0xA1, al
|
|
|
|
mov al, 0x01
|
|
out 0x21, al
|
|
out 0xA1, al
|
|
|
|
mov al, 0xB8
|
|
out 0x21, al
|
|
mov al, 0xBD
|
|
out 0xA1, al
|
|
|
|
mov al, 00110100b
|
|
out 43h, al
|
|
mov al, 0xFF
|
|
out 40h, al
|
|
out 40h, al
|
|
|
|
xor ax, ax
|
|
mov ds, ax
|
|
mov al, [BOOT_LO.shutdown_type]
|
|
cmp al, SYSTEM_RESTART
|
|
je .restart
|
|
|
|
cmp al, SYSTEM_SHUTDOWN
|
|
je .APM_PowerOff
|
|
|
|
mov word[0x0472], 0x1234
|
|
jmp 0xF000:0xFFF0
|
|
|
|
.APM_PowerOff:
|
|
mov ax, 5304h
|
|
xor bx, bx
|
|
int 15h
|
|
;!!!!!!!!!!!!!!!!!!!!!!!!
|
|
mov ax, 0x5300
|
|
xor bx, bx
|
|
int 0x15
|
|
push ax
|
|
|
|
mov ax, 0x5301
|
|
xor bx, bx
|
|
int 0x15
|
|
|
|
mov ax, 0x5308
|
|
mov bx, 1
|
|
mov cx, bx
|
|
int 0x15
|
|
|
|
mov ax, 0x530E
|
|
xor bx, bx
|
|
pop cx
|
|
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, 0x5307
|
|
mov bx, 1
|
|
mov cx, 3
|
|
int 0x15
|
|
;!!!!!!!!!!!!!!!!!!!!!!!!
|
|
jmp $
|
|
|
|
.restart:
|
|
|
|
; (hint by Black_mirror)
|
|
; We must read data from keyboard port,
|
|
; because there may be situation when previous keyboard interrupt is lost
|
|
; (due to return to real mode and IRQ reprogramming)
|
|
; and next interrupt will not be generated (as keyboard waits for handling)
|
|
|
|
mov cx, 16
|
|
@@:
|
|
in al, 0x64
|
|
test al, 1
|
|
jz @F
|
|
in al, 0x60
|
|
loop @B
|
|
@@:
|
|
|
|
; bootloader interface
|
|
push 0x1000
|
|
pop ds
|
|
push 0
|
|
pop es
|
|
mov si, [es:BOOT_LO.kernel_restart]
|
|
mov ax, 'KL'
|
|
jmp 0x1000:0000
|
|
|
|
align 4
|
|
org restart_code_start + $
|
|
restart_code_end:
|
|
|
|
org $+OS_BASE
|
|
use32
|