Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
redox-os
kernel
Commits
9b4ce0d0
Verified
Commit
9b4ce0d0
authored
Mar 11, 2021
by
4lDO2
🖖
Browse files
WIP: Fix userspace ACPI shutdown.
parent
b2e131b5
Changes
3
Hide whitespace changes
Inline
Side-by-side
src/arch/x86_64/stop.rs
View file @
9b4ce0d0
...
...
@@ -27,29 +27,47 @@ pub unsafe extern fn kreset() -> ! {
unreachable!
();
}
#[no_mangle]
pub
unsafe
extern
fn
kstop
()
->
!
{
println!
(
"kstop"
);
#[cfg(feature
=
"acpi"
)]
fn
userspace_acpi_shutdown
()
{
log
::
info!
(
"Notifying any potential ACPI driver"
);
// Tell whatever driver that handles ACPI, that it should enter the S5 state (i.e.
// shutdown).
if
!
acpi
::
register_kstop
()
{
// There was no context to switch to.
log
::
info!
(
"No ACPI driver was alive to handle shutdown."
);
return
;
}
log
::
info!
(
"Waiting one second for ACPI driver to run the shutdown sequence."
);
let
(
initial_s
,
initial_ns
)
=
time
::
monotonic
();
// FIXME: RPC into userspace, maybe allowing the kernel ACPI scheme to support e.g. registering
// an event queue, so that a special file can only be read/written when about to shut down.
// Since this driver is a userspace process, and we do not use any magic like directly
// context switching, we have to wait for the userspace driver to complete, with a timeout.
//
// We switch context, and wait for one second.
loop
{
// TODO: Switch directly to whichever process is handling the kstop pipe. We would add an
// event flag like EVENT_DIRECT, which has already been suggested for IRQs.
// TODO: Waitpid with timeout? Because, what if the ACPI driver would crash?
let
_
=
unsafe
{
context
::
switch
()
};
let
(
current_s
,
current_ns
)
=
time
::
monotonic
();
#[cfg(feature
=
"acpi"
)]
{
// Tell whatever driver that handles ACPI, that it should enter the S5 state (i.e.
// shutdown).
acpi
::
register_kstop
();
let
diff_s
=
current_s
-
initial_s
;
let
diff_part_ns
=
current_ns
-
initial_ns
;
let
diff_ns
=
diff_s
*
1_000_000_000
+
diff_part_ns
;
// Since this driver is a userspace process, and we do not use any magic like directly
// context switching, we have to wait for the userspace driver to complete, with a timeout.
//
// We switch context, and wait for one second.
while
time
::
monotonic
()
.0
<
1
{
if
!
context
::
switch
()
{
break
;
}
if
diff_ns
>
1_000_000_000
{
log
::
info!
(
"Timeout reached, thus falling back to other shutdown methods."
);
return
;
}
}
}
#[no_mangle]
pub
unsafe
extern
fn
kstop
()
->
!
{
log
::
info!
(
"Running kstop()"
);
#[cfg(feature
=
"acpi"
)]
userspace_acpi_shutdown
();
// Magic shutdown code for bochs and qemu (older versions).
for
c
in
"Shutdown"
.bytes
()
{
...
...
src/context/context.rs
View file @
9b4ce0d0
...
...
@@ -34,7 +34,7 @@ pub enum Status {
Runnable
,
Blocked
,
Stopped
(
usize
),
Exited
(
usize
)
Exited
(
usize
)
,
}
#[derive(Copy,
Clone,
Debug)]
...
...
src/syscall/process.rs
View file @
9b4ce0d0
...
...
@@ -1128,6 +1128,8 @@ pub fn fexec(fd: FileHandle, arg_ptrs: &[[usize; 2]], var_ptrs: &[[usize; 2]]) -
pub
fn
exit
(
status
:
usize
)
->
!
{
ptrace
::
breakpoint_callback
(
PTRACE_STOP_EXIT
,
Some
(
ptrace_event!
(
PTRACE_STOP_EXIT
,
status
)));
let
pid
;
{
let
context_lock
=
{
let
contexts
=
context
::
contexts
();
...
...
@@ -1136,7 +1138,7 @@ pub fn exit(status: usize) -> ! {
};
let
mut
close_files
=
Vec
::
new
();
let
pid
=
{
pid
=
{
let
mut
context
=
context_lock
.write
();
{
let
mut
lock
=
context
.files
.write
();
...
...
@@ -1148,6 +1150,22 @@ pub fn exit(status: usize) -> ! {
context
.id
};
// TODO: Find a better way to implement this, perhaps when the init process calls exit.
if
pid
==
ContextId
::
from
(
1
)
{
println!
(
"Main kernel thread exited with status {:X}"
,
status
);
extern
{
fn
kreset
()
->
!
;
fn
kstop
()
->
!
;
}
if
status
==
SIGTERM
{
unsafe
{
kreset
();
}
}
else
{
unsafe
{
kstop
();
}
}
}
// Files must be closed while context is valid so that messages can be passed
for
(
_fd
,
file_opt
)
in
close_files
.drain
(
..
)
.enumerate
()
{
if
let
Some
(
file
)
=
file_opt
{
...
...
@@ -1214,26 +1232,10 @@ pub fn exit(status: usize) -> ! {
// Alert any tracers waiting of this process
ptrace
::
close_tracee
(
pid
);
if
pid
==
ContextId
::
from
(
1
)
{
println!
(
"Main kernel thread exited with status {:X}"
,
status
);
extern
{
fn
kreset
()
->
!
;
fn
kstop
()
->
!
;
}
if
status
==
SIGTERM
{
unsafe
{
kreset
();
}
}
else
{
unsafe
{
kstop
();
}
}
}
}
let
_
=
unsafe
{
context
::
switch
()
};
unreachable!
();
unreachable!
()
}
pub
fn
getpid
()
->
Result
<
ContextId
>
{
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment