aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@linux.intel.com>2010-03-30 16:06:39 -0700
committerH. Peter Anvin <hpa@linux.intel.com>2010-03-30 16:10:13 -0700
commitd6fb0861c55f062797c8706f484bd47ae0f94568 (patch)
tree058691551709427756f9d2469c1eaf47cd59917f
parentb6e84b7f93c5b4a0cffd132f3c6dbf6bf58ba2b9 (diff)
downloadsyslinux-d6fb0861c55f062797c8706f484bd47ae0f94568.tar.gz
syslinux-d6fb0861c55f062797c8706f484bd47ae0f94568.tar.xz
syslinux-d6fb0861c55f062797c8706f484bd47ae0f94568.zip
core: move idle handling into protected mode
Do the actual idling in protected mode. This both allows PM code a more efficient interface, but also handles bugs in HVM implementations which don't handle HLT in real mode. Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
-rw-r--r--com32/include/sys/cpu.h5
-rw-r--r--com32/include/syslinux/idle.h1
-rw-r--r--com32/include/syslinux/pmapi.h3
-rw-r--r--com32/lib/syslinux/idle.c24
-rw-r--r--core/fs/pxe/idle.c4
-rw-r--r--core/idle.c49
-rw-r--r--core/idle.inc30
-rw-r--r--core/include/core.h8
-rw-r--r--core/pmapi.c3
9 files changed, 88 insertions, 39 deletions
diff --git a/com32/include/sys/cpu.h b/com32/include/sys/cpu.h
index d96ec665..a798a840 100644
--- a/com32/include/sys/cpu.h
+++ b/com32/include/sys/cpu.h
@@ -105,7 +105,10 @@ static inline void cpu_relax(void)
asm volatile ("rep ; nop");
}
-/* These are local cli/sti; not SMP-safe!!! */
+static inline void hlt(void)
+{
+ asm volatile ("hlt");
+}
static inline void cli(void)
{
diff --git a/com32/include/syslinux/idle.h b/com32/include/syslinux/idle.h
index 4c5947b7..6a45236e 100644
--- a/com32/include/syslinux/idle.h
+++ b/com32/include/syslinux/idle.h
@@ -33,5 +33,6 @@
#define _SYSLINUX_IDLE_H
void syslinux_idle(void);
+void syslinux_reset_idle(void);
#endif
diff --git a/com32/include/syslinux/pmapi.h b/com32/include/syslinux/pmapi.h
index 5631dcba..f583deae 100644
--- a/com32/include/syslinux/pmapi.h
+++ b/com32/include/syslinux/pmapi.h
@@ -62,6 +62,9 @@ struct com32_pmapi {
struct _DIR_ *(*opendir)(const char *);
struct dirent *(*readdir)(struct _DIR_ *);
int (*closedir)(struct _DIR_ *);
+
+ void (*idle)(void);
+ void (*reset_idle)(void);
};
#endif /* _SYSLINUX_PMAPI_H */
diff --git a/com32/lib/syslinux/idle.c b/com32/lib/syslinux/idle.c
index 8a0d206c..ddaa7fcd 100644
--- a/com32/lib/syslinux/idle.c
+++ b/com32/lib/syslinux/idle.c
@@ -33,25 +33,15 @@
#include <stddef.h>
#include <com32.h>
-#include <sys/cpu.h>
+#include <syslinux/pmapi.h>
#include <syslinux/idle.h>
-void syslinux_idle(void)
+void syslinux_reset_idle(void)
{
- static int do_idle = 1;
- static const com32sys_t sys_idle = {
- .eax.l = 0x0013,
- };
- com32sys_t idle_result;
-
- /* This call isn't supported on SYSLINUX < 3.08, but all it does
- is return an error, so we don't care. */
-
- if (do_idle) {
- __intcall(0x22, &sys_idle, &idle_result);
-
- do_idle = ~idle_result.eflags.l & EFLAGS_CF;
- }
+ __com32.cs_pm->reset_idle();
+}
- cpu_relax();
+void syslinux_idle(void)
+{
+ __com32.cs_pm->idle();
}
diff --git a/core/fs/pxe/idle.c b/core/fs/pxe/idle.c
index 5393ae1d..0538b163 100644
--- a/core/fs/pxe/idle.c
+++ b/core/fs/pxe/idle.c
@@ -19,7 +19,7 @@
#include <sys/cpu.h>
#include "pxe.h"
-static void pxe_idle_poll(void)
+static int pxe_idle_poll(void)
{
static __lowmem char junk_pkt[PKTBUF_SIZE];
static __lowmem t_PXENV_UDP_READ read_buf;
@@ -34,6 +34,8 @@ static void pxe_idle_poll(void)
read_buf.buffer = FAR_PTR(junk_pkt);
pxe_call(PXENV_UDP_READ, &read_buf);
+
+ return 0;
}
static uint32_t pxe_detect_nic_type(void)
diff --git a/core/idle.c b/core/idle.c
new file mode 100644
index 00000000..3f57393b
--- /dev/null
+++ b/core/idle.c
@@ -0,0 +1,49 @@
+/* -*- fundamental -*- ---------------------------------------------------
+ *
+ * Copyright 2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * idle.c:
+ *
+ * This function provided protected-mode access to the idle handling.
+ * It needs to be carefully coordinated with idle.inc, which provides
+ * idle services to real-mode code.
+ */
+
+#include "core.h"
+#include <sys/cpu.h>
+
+#define TICKS_TO_IDLE 4 /* Also in idle.inc */
+
+extern uint32_t _IdleTimer;
+extern uint16_t NoHalt;
+
+int (*idle_hook_func)(void);
+
+void reset_idle(void)
+{
+ _IdleTimer = jiffies();
+}
+
+void __idle(void)
+{
+ if (jiffies() - _IdleTimer < TICKS_TO_IDLE)
+ return;
+
+ if (idle_hook_func && idle_hook_func())
+ return; /* Nonzero return = do not idle */
+
+ if (NoHalt)
+ cpu_relax();
+ else
+ hlt();
+}
diff --git a/core/idle.inc b/core/idle.inc
index 8d699733..0da03eff 100644
--- a/core/idle.inc
+++ b/core/idle.inc
@@ -1,7 +1,7 @@
;; -*- fundamental -*- ---------------------------------------------------
;;
;; Copyright 2008 H. Peter Anvin - All Rights Reserved
-;; Copyright 2009 Intel Corporation; author: H. Peter Anvin
+;; Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
@@ -12,12 +12,12 @@
;; -----------------------------------------------------------------------
section .text16
-TICKS_TO_IDLE equ 4
+TICKS_TO_IDLE equ 4 ; Also in idle.c
reset_idle:
push eax
mov eax,[cs:__jiffies]
- mov [cs:IdleTimer],eax
+ mov [cs:_IdleTimer],eax
pop eax
sti ; Guard against BIOS/PXE brokenness...
ret
@@ -54,19 +54,15 @@ do_idle:
pop si
sti
.ok:
+ ; Don't spend time jumping to PM unless we're actually idle...
+
mov eax,[__jiffies]
- sub eax,[IdleTimer]
+ sub eax,[_IdleTimer]
cmp eax,TICKS_TO_IDLE
jb .done
-
- mov eax,[idle_hook_func]
- and eax,eax
- jz .no_idle_hook
- pm_call eax
-.no_idle_hook:
- cmp word [NoHalt],0
- jne .done
- hlt
+
+ extern __idle
+ pm_call __idle
.done:
pop es
pop ds
@@ -74,13 +70,13 @@ do_idle:
.ret: ret
section .data16
- alignz 4
- global idle_hook_func
-idle_hook_func dd 0
+ alignz 2
+ global NoHalt
NoHalt dw 0
hlt_err db 'ERROR: idle with IF=0', CR, LF, 0
section .bss16
+ global _IdleTimer
alignb 4
-IdleTimer resd 1
+_IdleTimer resd 1
diff --git a/core/include/core.h b/core/include/core.h
index f03da813..eb7bfcdb 100644
--- a/core/include/core.h
+++ b/core/include/core.h
@@ -21,12 +21,14 @@ extern void getlinsec(void);
/* getc.inc */
extern void core_open(void);
-/* idle.inc */
-extern void (*idle_hook_func)(void);
-
/* hello.c */
extern void myputs(const char*);
+/* idle.c */
+extern int (*idle_hook_func)(void);
+extern void __idle(void);
+extern void reset_idle(void);
+
/* mem/malloc.c, mem/free.c, mem/init.c */
extern void *malloc(size_t);
extern void *lmalloc(size_t);
diff --git a/core/pmapi.c b/core/pmapi.c
index 88a7f34f..3313ceaf 100644
--- a/core/pmapi.c
+++ b/core/pmapi.c
@@ -29,4 +29,7 @@ const struct com32_pmapi pm_api_vector =
.opendir = opendir,
.readdir = readdir,
.closedir = closedir,
+
+ .idle = __idle,
+ .reset_idle = reset_idle,
};