kolibrios/kernel/trunk/boot/shutdown.inc

408 lines
10 KiB
PHP
Raw Normal View History

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2024. 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 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
align 4
system_shutdown: ; shut down the system
cmp [BOOT.shutdown_type], SYSTEM_SHUTDOWN
jb @F
cmp [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
movzx eax, [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
cmp [BOOT.shutdown_type], SYSTEM_SHUTDOWN
jne not_power_off
; system_power_off
mov ebx, [acpi_fadt_base]
test ebx, ebx
jz no_acpi
cmp [ebx+ACPI_TABLE.Signature], 'FACP'
jne no_acpi
mov esi, [acpi_ssdt_base] ; first SSDT is DSDT
test esi, esi
jz no_acpi
cmp [esi+ACPI_TABLE.Signature], 'DSDT'
jne no_acpi
mov eax, [esi+ACPI_TABLE.Length]
sub eax, 36+4
jbe no_acpi
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
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
inc esi
mov ch, [esi]
@@:
jmp do_acpi_power_off
.scan_dsdt_cont:
inc esi
dec eax
jnz .scan_dsdt
jmp no_acpi
do_acpi_power_off:
mov edx, [ebx+ACPI_FADT.SMI_CMD]
test edx, edx
jz .nosmi
mov al, [ebx+ACPI_FADT.ACPI_ENABLE]
out dx, al
mov edx, [ebx+ACPI_FADT.PM1a_CNT_BLK]
@@:
in ax, dx
test al, 1
jz @b
.nosmi:
and cx, 0x0707
shl cx, 2
or cx, 0x2020
mov edx, [ebx+ACPI_FADT.PM1a_CNT_BLK]
in ax, dx
and ax, 203h
or ah, cl
out dx, ax
mov edx, [ebx+ACPI_FADT.PM1b_CNT_BLK]
test edx, edx
jz @f
in ax, dx
and ax, 203h
or ah, ch
out dx, ax
@@:
jmp no_acpi
not_power_off:
cmp [BOOT.shutdown_type], SYSTEM_REBOOT
jnz not_reboot
; try to reboot via ACPI fixed features
mov ebx, [acpi_fadt_base]
test ebx, ebx
jz no_acpi
cmp [ebx+ACPI_TABLE.Signature], 'FACP'
jne no_acpi
cmp [ebx+ACPI_FADT.Length], ACPI_FADT.RESET_VALUE
jbe no_acpi
test [ebx+ACPI_FADT.Flags], 1 SHL 10 ; reset_reg_supported
jz no_acpi
cmp [ebx+ACPI_FADT.RESET_REG.ASID], ASID.SYSTEM_IO
jnz no_acpi
cmp [ebx+ACPI_FADT.RESET_REG.BitWidth], 8
jnz no_acpi
cmp [ebx+ACPI_FADT.RESET_REG.BitOffset], 0
jnz no_acpi
cmp [ebx+ACPI_FADT.RESET_REG.AccessSize], ACCESS_SIZE.BYTE
ja no_acpi
cmp [ebx+ACPI_FADT.RESET_REG.Address.hi], 0
jnz no_acpi
; 'enable' ACPI
mov edx, [ebx+ACPI_FADT.SMI_CMD]
test edx, edx
jz .nosmi
mov al, [ebx+ACPI_FADT.ACPI_ENABLE]
out dx, al
mov edx, [ebx+ACPI_FADT.PM1a_CNT_BLK]
@@:
in ax, dx
test al, 1
jz @b
.nosmi:
mov edx, [ebx+ACPI_FADT.RESET_REG.Address.lo]
movzx eax, [ebx+ACPI_FADT.RESET_VALUE]
out dx, al
jmp no_acpi
not_reboot:
no_acpi:
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
jmp 0x50000
align 4
restart_code_start:
org 0x50000
cmp [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