kernel: restart, reboot and power off

git-svn-id: svn://kolibrios.org@6244 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
Sergey Semyonov (Serge) 2016-02-18 02:03:38 +00:00
parent 465434cb12
commit 50e97c60fa
6 changed files with 277 additions and 396 deletions

View File

@ -1,6 +1,6 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Copyright (C) KolibriOS team 2004-2016. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; Shutdown for Menuet ;;
@ -13,11 +13,212 @@
$Revision$
use32
become_real:
align 4
system_shutdown: ; shut down the system
cmp byte [BOOT_VARS+0x9030], 1
jne @F
ret
@@:
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
lgdt [realmode_gdt-OS_BASE]
call IRQ_mask_all
mov eax, [OS_BASE + 0x9030]
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 [0x9030], 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:
jmp 0x50000
align 4
restart_code_start:
org 0x50000
cmp byte [0x9030], 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
@ -26,108 +227,64 @@ use16
mov fs, ax
mov gs, ax
mov ss, ax
mov eax, cr0
and eax, not 80000001h
mov cr0, eax
jmp 0x1000:pr_mode_exit
jmp 0x5000:.real_mode
pr_mode_exit:
align 4
.real_mode:
; setup stack
mov ax, 0x3000
mov ss, ax
mov esp, 0x0EC00
; setup ds
push cs
pop ds
lidt [old_ints_h]
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
call rdelay
out 0xA0, al
call rdelay
mov al, 0x08
out 0x21, al
call rdelay
mov al, 0x70
out 0xA1, al
call rdelay
mov al, 0x04
out 0x21, al
call rdelay
mov al, 0x02
out 0xA1, al
call rdelay
mov al, 0x01
out 0x21, al
call rdelay
out 0xA1, al
call rdelay
mov al, 0xB8
out 0x21, al
call rdelay
mov al, 0xBD
out 0xA1, al
sti
temp_3456:
mov al, 00110100b
out 43h, al
mov al, 0xFF
out 40h, al
out 40h, al
xor ax, ax
mov es, ax
mov al, byte [es:0x9030]
cmp al, 1
jl nbw
cmp al, 4
jle nbw32
mov ds, ax
mov al, [0x9030]
cmp al, SYSTEM_RESTART
je .restart
nbw:
in al, 0x60
cmp al, 6
jae nbw
mov bl, al
nbw2:
in al, 0x60
cmp al, bl
je nbw2
cmp al, 240;ax,240
jne nbw31
mov al, bl
dec ax
jmp nbw32
nbw31:
add bl, 128
cmp al, bl
jne nbw
sub al, 129
cmp al, SYSTEM_SHUTDOWN
je .APM_PowerOff
nbw32:
dec ax
dec ax ; 2 = power off
jnz no_apm_off
call APM_PowerOff
jmp $
no_apm_off:
if ~ defined extended_primary_loader ; kernel restarting is not supported
dec ax ; 3 = reboot
jnz restart_kernel ; 4 = restart kernel
end if
push 0x40
pop ds
mov word[0x0072], 0x1234
mov word[0x0472], 0x1234
jmp 0xF000:0xFFF0
rdelay:
ret
APM_PowerOff:
.APM_PowerOff:
mov ax, 5304h
xor bx, bx
int 15h
@ -166,57 +323,24 @@ APM_PowerOff:
mov cx, 3
int 0x15
;!!!!!!!!!!!!!!!!!!!!!!!!
ret
jmp $
if ~ defined extended_primary_loader
restart_kernel:
mov ax, 0x0003 ; set text mode for screen
int 0x10
jmp 0x4000:0000
restart_kernel_4000:
cli
push ds
pop es
mov cx, 0x8000
push cx
push 0x7100
pop ds
xor si, si
xor di, di
rep movsw
pop cx
mov ds, cx
push 0x2000
pop es
rep movsw
push 0x9000
pop ds
push 0x3000
pop es
mov cx, 0xE000/2
rep movsw
wbinvd ; write and invalidate cache
mov al, 00110100b
out 43h, al
jcxz $+2
mov al, 0xFF
out 40h, al
jcxz $+2
out 40h, al
jcxz $+2
sti
.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
@ -224,5 +348,10 @@ restart_kernel_4000:
mov si, kernel_restart_bootblock
mov ax, 'KL'
jmp 0x1000:0000
end if
align 4
org restart_code_start + $
restart_code_end:
org $+OS_BASE
use32

View File

@ -358,6 +358,10 @@ STDIN_FILENO equ 0
STDOUT_FILENO equ 1
STDERR_FILENO equ 2
SYSTEM_SHUTDOWN equ 2
SYSTEM_REBOOT equ 3
SYSTEM_RESTART equ 4
struct SYSCALL_STACK
_eip dd ?
_edi dd ? ; +4

View File

@ -173,11 +173,11 @@ end if
vmode db '/sys/drivers/VMODE.MDR',0
;vrr_m db 'VRR_M',0
kernel_file_load:
; load kernel.mnt to 0x7000:0
; load kernel.mnt to _CLEAN_ZONE
dd 0 ; subfunction
dq 0 ; offset in file
dd 0x30000 ; number of bytes to read
dd OS_BASE + 0x71000 ; buffer for data
dd 0x31000 ; number of bytes to read
dd _CLEAN_ZONE ; buffer for data
db '/RD/1/KERNEL.MNT',0
dev_data_path db '/RD/1/DRIVERS/DEVICES.DAT',0
@ -371,12 +371,10 @@ os_stack_seg rd 1
srv.fd rd 1
srv.bk rd 1
align 16
_display display_t
LFBAddress dd ?
SCR_MODE rw 2

View File

@ -455,7 +455,27 @@ ACPI_FADT_SIGN equ 0x50434146
acpi_locate:
push ebx
push edi
movzx ebx, word [0x40E]
shl ebx, 4
lea ecx, [ebx+1024]
call .check
test ebx, ebx
jz @F
jmp .done
@@:
mov ebx, ACPI_HI_RSDP_WINDOW_START
mov edi, ACPI_HI_RSDP_WINDOW_END
call .check
.done:
mov eax, ebx
pop edi
pop ebx
ret
.check:
cmp [ebx], dword 0x20445352
jne .next
@ -472,17 +492,12 @@ acpi_locate:
test al, al
jnz .next
mov eax, ebx
pop ebx
ret
.next:
add ebx, 16
cmp ebx, ACPI_HI_RSDP_WINDOW_END
cmp ebx, edi
jb .check
pop ebx
xor eax, eax
xor ebx, ebx
ret
align 4

View File

@ -253,7 +253,7 @@ B32:
mov fs, ax
mov gs, ax
mov ss, ax
mov esp, 0x006CC00 ; Set stack
mov esp, TMP_STACK_TOP ; Set stack
; CLEAR 0x280000 - HEAP_BASE
@ -305,12 +305,7 @@ B32:
align 4
bios32_entry dd ?
tmp_page_tabs dd ?
use16
org $-0x10000
include "boot/shutdown.inc" ; shutdown or restart
org $+0x10000
ap_init16:
cli
lgdt [cs:gdts_ap-ap_init16]
@ -5722,266 +5717,6 @@ undefined_syscall: ; Undefined system call
mov [esp + 32], dword -1
ret
align 4
system_shutdown: ; shut down the system
cmp byte [BOOT_VARS+0x9030], 1
jne @F
ret
@@:
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
if ~ defined extended_primary_loader
; load kernel.mnt to 0x7000:0
mov ebx, kernel_file_load
pushad
call file_system_lfn
popad
mov esi, restart_kernel_4000+OS_BASE+0x10000 ; move kernel re-starter to 0x4000:0
mov edi, OS_BASE+0x40000
mov ecx, 1000
rep movsb
end if
; mov esi, BOOT_VAR ; restore 0x0 - 0xffff
; mov edi, OS_BASE
; mov ecx, 0x10000/4
; cld
; rep movsd
call IRQ_mask_all
cmp byte [OS_BASE + 0x9030], 2
jnz no_acpi_power_off
; scan for RSDP
; 1) The first 1 Kb of the Extended BIOS Data Area (EBDA).
movzx eax, word [OS_BASE + 0x40E]
shl eax, 4
jz @f
mov ecx, 1024/16
call scan_rsdp
jnc .rsdp_found
@@:
; 2) The BIOS read-only memory space between 0E0000h and 0FFFFFh.
mov eax, 0xE0000
mov ecx, 0x2000
call scan_rsdp
jc no_acpi_power_off
.rsdp_found:
mov esi, [eax+16] ; esi contains physical address of the RSDT
mov ebp, [ipc_tmp]
stdcall map_page, ebp, esi, PG_READ
lea eax, [esi+1000h]
lea edx, [ebp+1000h]
stdcall map_page, edx, eax, PG_READ
and esi, 0xFFF
add esi, ebp
cmp dword [esi], 'RSDT'
jnz no_acpi_power_off
mov ecx, [esi+4]
sub ecx, 24h
jbe no_acpi_power_off
shr ecx, 2
add esi, 24h
.scan_fadt:
lodsd
mov ebx, eax
lea eax, [ebp+2000h]
stdcall map_page, eax, ebx, PG_READ
lea eax, [ebp+3000h]
add ebx, 0x1000
stdcall map_page, eax, ebx, PG_READ
and ebx, 0xFFF
lea ebx, [ebx+ebp+2000h]
cmp dword [ebx], 'FACP'
jz .fadt_found
loop .scan_fadt
jmp no_acpi_power_off
.fadt_found:
; ebx is linear address of FADT
mov edi, [ebx+40] ; physical address of the DSDT
lea eax, [ebp+4000h]
stdcall map_page, eax, edi, PG_READ
lea eax, [ebp+5000h]
lea esi, [edi+0x1000]
stdcall map_page, eax, esi, PG_READ
and esi, 0xFFF
sub edi, esi
cmp dword [esi+ebp+4000h], 'DSDT'
jnz no_acpi_power_off
mov eax, [esi+ebp+4004h] ; DSDT length
sub eax, 36+4
jbe no_acpi_power_off
add esi, 36
.scan_dsdt:
cmp dword [esi+ebp+4000h], '_S5_'
jnz .scan_dsdt_cont
cmp byte [esi+ebp+4000h+4], 12h ; DefPackage opcode
jnz .scan_dsdt_cont
mov dl, [esi+ebp+4000h+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+ebp+4000h+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
cmp esi, 0x1000
jb @f
sub esi, 0x1000
add edi, 0x1000
push eax
lea eax, [ebp+4000h]
stdcall map_page, eax, edi, PG_READ
push PG_READ
lea eax, [edi+1000h]
push eax
lea eax, [ebp+5000h]
push eax
stdcall map_page
pop eax
@@:
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 $
scan_rsdp:
add eax, OS_BASE
.s:
cmp dword [eax], 'RSD '
jnz .n
cmp dword [eax+4], 'PTR '
jnz .n
xor edx, edx
xor esi, esi
@@:
add dl, [eax+esi]
inc esi
cmp esi, 20
jnz @b
test dl, dl
jz .ok
.n:
add eax, 10h
loop .s
stc
.ok:
ret
no_acpi_power_off:
call create_trampoline_pgmap
mov cr3, eax
jmp become_real+0x10000
iglobal
align 4
realmode_gdt:
; selector 0 - not used
dw 23
dd realmode_gdt-OS_BASE
dw 0
; selector 8 - code from 1000:0000 to 1000:FFFF
dw 0FFFFh
dw 0
db 1
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
endg
if ~ lang eq sp
diff16 "end of .text segment",0,$

View File

@ -42,7 +42,7 @@ include "gui/event.inc"
include "gui/font.inc"
include "gui/button.inc"
; shutdown
include "boot/shutdown.inc" ; kernel shutdown
; file system