Implemented first basic APM driver. Only tested with QEMU so far, that's why
it's currently disabled. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16120 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
bfb4078864
commit
afd6dfc8b4
@ -1,20 +1,25 @@
|
||||
/*
|
||||
* Copyright 2006, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Copyright 2005, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
|
||||
*
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _KERNEL_ARCH_PLATFORM_H
|
||||
#define _KERNEL_ARCH_PLATFORM_H
|
||||
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
struct kernel_args;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
status_t arch_platform_init(struct kernel_args *kernelArgs);
|
||||
status_t arch_platform_init_post_vm(struct kernel_args *kernelArgs);
|
||||
status_t arch_platform_init_post_thread(struct kernel_args *kernelArgs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
@ -1,9 +1,38 @@
|
||||
/*
|
||||
* Copyright 2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef KERNEL_APM_H
|
||||
#define KERNEL_APM_H
|
||||
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
struct kernel_args;
|
||||
|
||||
|
||||
// int 0x15 APM definitions
|
||||
#define BIOS_APM_CHECK 0x5300
|
||||
#define BIOS_APM_CONNECT_32_BIT 0x5303
|
||||
#define BIOS_APM_DISCONNECT 0x5304
|
||||
#define BIOS_APM_CPU_IDLE 0x5305
|
||||
#define BIOS_APM_CPU_BUSY 0x5306
|
||||
#define BIOS_APM_SET_STATE 0x5307
|
||||
#define BIOS_APM_ENABLE 0x5308
|
||||
#define BIOS_APM_GET_POWER_STATUS 0x530a
|
||||
#define BIOS_APM_GET_EVENT 0x530b
|
||||
#define BIOS_APM_GET_STATE 0x530c
|
||||
#define BIOS_APM_VERSION 0x530e
|
||||
#define BIOS_APM_ENGAGE 0x530f
|
||||
|
||||
// APM devices
|
||||
#define APM_ALL_DEVICES 0x0001
|
||||
|
||||
// APM power states
|
||||
#define APM_POWER_STATE_ENABLED 0x0000
|
||||
#define APM_POWER_STATE_STANDBY 0x0001
|
||||
#define APM_POWER_STATE_SUSPEND 0x0002
|
||||
#define APM_POWER_STATE_OFF 0x0003
|
||||
|
||||
typedef struct apm_info {
|
||||
uint16 version;
|
||||
@ -18,4 +47,16 @@ typedef struct apm_info {
|
||||
} apm_info;
|
||||
|
||||
|
||||
#ifndef _BOOT_MODE
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
status_t apm_init(struct kernel_args *args);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // !_BOOT_MODE
|
||||
|
||||
#endif /* KERNEL_APM_H */
|
||||
|
@ -19,11 +19,13 @@
|
||||
#define APM_CODE16_SEGMENT 0x30
|
||||
#define APM_DATA_SEGMENT 0x38
|
||||
|
||||
#define BIOS_DATA_SEGMENT 0x40
|
||||
|
||||
#ifndef _ASSEMBLER
|
||||
// this file can also be included from assembler as well
|
||||
// (and is in arch_interrupts.S)
|
||||
|
||||
#define DOUBLE_FAULT_TSS_BASE_SEGMENT 8
|
||||
#define DOUBLE_FAULT_TSS_BASE_SEGMENT 9
|
||||
#define TSS_BASE_SEGMENT (DOUBLE_FAULT_TSS_BASE_SEGMENT + smp_get_num_cpus())
|
||||
#define TLS_BASE_SEGMENT (TSS_BASE_SEGMENT + smp_get_num_cpus())
|
||||
#define APM_BASE_SEGMENT (TLS_BASE_SEGMENT + smp_get_num_cpus())
|
||||
|
@ -6,7 +6,13 @@ UsePrivateHeaders [ FDirName kernel disk_device_manager ] ;
|
||||
UsePrivateHeaders [ FDirName graphics vesa ] ;
|
||||
UsePrivateHeaders [ FDirName storage ] ;
|
||||
|
||||
SubDirC++Flags -fno-rtti ;
|
||||
{
|
||||
local defines = _BOOT_MODE ;
|
||||
|
||||
defines = [ FDefines $(defines) ] ;
|
||||
SubDirCcFlags $(defines) -Wall -Wno-multichar ;
|
||||
SubDirC++Flags $(defines) -Wall -Wno-multichar -fno-rtti ;
|
||||
}
|
||||
|
||||
KernelMergeObject boot_platform_bios_ia32.o :
|
||||
shell.S
|
||||
|
@ -20,12 +20,6 @@
|
||||
#endif
|
||||
|
||||
|
||||
// int 0x15 APM definitions
|
||||
#define BIOS_APM_CHECK 0x5300
|
||||
#define BIOS_APM_CONNECT_32_BIT 0x5303
|
||||
#define BIOS_APM_DISCONNECT 0x5304
|
||||
|
||||
|
||||
status_t
|
||||
apm_init(void)
|
||||
{
|
||||
@ -68,8 +62,11 @@ apm_init(void)
|
||||
regs.eax = BIOS_APM_CONNECT_32_BIT;
|
||||
regs.ebx = 0;
|
||||
call_bios(0x15, ®s);
|
||||
if ((regs.flags & CARRY_FLAG) != 0)
|
||||
if ((regs.flags & CARRY_FLAG) != 0) {
|
||||
// reset the version, so that the kernel won't try to use APM
|
||||
info.version = 0;
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
info.code32_segment_base = regs.eax & 0xffff;
|
||||
info.code32_segment_offset = regs.ebx;
|
||||
|
@ -242,3 +242,10 @@ arch_platform_init_post_vm(struct kernel_args *kernelArgs)
|
||||
{
|
||||
return sPPCPlatform->InitPostVM(kernelArgs);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_platform_init_post_thread(struct kernel_args *kernelArgs)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ KernelStaticLibrary libx86 :
|
||||
arch_interrupts.S
|
||||
arch_system_info.c
|
||||
arch_user_debugger.cpp
|
||||
apm.cpp
|
||||
bios.cpp
|
||||
cpuid.S
|
||||
|
||||
|
216
src/system/kernel/arch/x86/apm.cpp
Normal file
216
src/system/kernel/arch/x86/apm.cpp
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright 2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include <KernelExport.h>
|
||||
|
||||
#include <apm.h>
|
||||
#include <descriptors.h>
|
||||
#include <boot/kernel_args.h>
|
||||
|
||||
|
||||
#define TRACE_APM
|
||||
#ifdef TRACE_APM
|
||||
# define TRACE(x) dprintf x
|
||||
#else
|
||||
# define TRACE(x) ;
|
||||
#endif
|
||||
|
||||
#define CARRY_FLAG 0x01
|
||||
|
||||
extern segment_descriptor *gGDT;
|
||||
extern void *gDmaAddress;
|
||||
extern addr_t gBiosBase;
|
||||
|
||||
static struct {
|
||||
uint32 offset;
|
||||
uint16 segment;
|
||||
} sAPMBiosEntry;
|
||||
|
||||
|
||||
struct bios_regs {
|
||||
bios_regs() : eax(0), ebx(0), ecx(0), edx(0), esi(0), flags(0) {}
|
||||
uint32 eax;
|
||||
uint32 ebx;
|
||||
uint32 ecx;
|
||||
uint32 edx;
|
||||
uint32 esi;
|
||||
uint32 flags;
|
||||
};
|
||||
|
||||
|
||||
static status_t
|
||||
call_apm_bios(bios_regs *regs)
|
||||
{
|
||||
asm volatile(
|
||||
"pushfl; "
|
||||
"pushl %%ebp; "
|
||||
"lcall *%%cs:sAPMBiosEntry; "
|
||||
"popl %%ebp; "
|
||||
"pushfl; "
|
||||
"popl %%edi; "
|
||||
"movl %%edi, %5; "
|
||||
"popfl; "
|
||||
: "=a" (regs->eax), "=b" (regs->ebx), "=c" (regs->ecx), "=d" (regs->edx),
|
||||
"=S" (regs->esi), "=m" (regs->flags)
|
||||
: "a" (regs->eax), "b" (regs->ebx), "c" (regs->ecx)
|
||||
: "memory", "edi", "cc");
|
||||
|
||||
if (regs->flags & CARRY_FLAG)
|
||||
return B_ERROR;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
apm_get_event(uint16 &event, uint16 &info)
|
||||
{
|
||||
bios_regs regs;
|
||||
regs.eax = BIOS_APM_GET_EVENT;
|
||||
|
||||
if (call_apm_bios(®s) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
event = regs.ebx & 0xffff;
|
||||
info = regs.ecx & 0xffff;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
apm_set_state(uint16 device, uint16 state)
|
||||
{
|
||||
bios_regs regs;
|
||||
regs.eax = BIOS_APM_SET_STATE;
|
||||
regs.ebx = device;
|
||||
regs.ecx = state;
|
||||
|
||||
return call_apm_bios(®s);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
apm_enable_power_management(uint16 device, bool enable)
|
||||
{
|
||||
bios_regs regs;
|
||||
regs.eax = BIOS_APM_ENABLE;
|
||||
regs.ebx = device;
|
||||
|
||||
return call_apm_bios(®s);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
apm_engage_power_management(uint16 device, bool enable)
|
||||
{
|
||||
bios_regs regs;
|
||||
regs.eax = BIOS_APM_ENGAGE;
|
||||
regs.ebx = device;
|
||||
|
||||
return call_apm_bios(®s);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
apm_driver_version(uint16 version)
|
||||
{
|
||||
dprintf("version: %x\n", version);
|
||||
bios_regs regs;
|
||||
regs.eax = BIOS_APM_VERSION;
|
||||
regs.ecx = version;
|
||||
|
||||
if (call_apm_bios(®s) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
dprintf("eax: %lx, flags: %lx\n", regs.eax, regs.flags);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
apm_daemon(void *arg, int iteration)
|
||||
{
|
||||
uint16 event;
|
||||
uint16 info;
|
||||
if (apm_get_event(event, info) != B_OK)
|
||||
return;
|
||||
|
||||
dprintf("APM event: %x, info: %x\n", event, info);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
apm_init(kernel_args *args)
|
||||
{
|
||||
apm_info &info = args->platform_args.apm;
|
||||
|
||||
TRACE(("apm_init()\n"));
|
||||
|
||||
if ((info.version & 0xf) < 2) {
|
||||
// no APM or connect failed
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
TRACE((" code32: 0x%x, 0x%lx, length 0x%x\n",
|
||||
info.code32_segment_base, info.code32_segment_offset, info.code32_segment_length));
|
||||
TRACE((" code16: 0x%x, length 0x%x\n",
|
||||
info.code16_segment_base, info.code16_segment_length));
|
||||
TRACE((" data: 0x%x, length 0x%x\n",
|
||||
info.data_segment_base, info.data_segment_length));
|
||||
|
||||
// TODO: remove me when tested on more hardware
|
||||
if (1)
|
||||
return B_OK;
|
||||
|
||||
// Apparently, some broken BIOS try to access segment 0x40 for the BIOS
|
||||
// data section - we make sure it can by setting up the GDT accordingly
|
||||
// (the first 640kB are mapped as DMA area in arch_vm_init()).
|
||||
addr_t biosData = (addr_t)gDmaAddress + 0x400;
|
||||
|
||||
set_segment_descriptor(&gGDT[BIOS_DATA_SEGMENT >> 3],
|
||||
biosData, B_PAGE_SIZE - biosData,
|
||||
DT_DATA_WRITEABLE, DPL_KERNEL);
|
||||
|
||||
// TODO: test if APM segments really are in the BIOS ROM area (especially the
|
||||
// data segment)
|
||||
|
||||
// setup APM GDTs
|
||||
|
||||
set_segment_descriptor(&gGDT[APM_CODE32_SEGMENT >> 3],
|
||||
gBiosBase + (info.code32_segment_base << 4) - 0xe0000, 0xffff,
|
||||
DT_CODE_READABLE, DPL_KERNEL);
|
||||
set_segment_descriptor(&gGDT[APM_CODE16_SEGMENT >> 3],
|
||||
gBiosBase + (info.code16_segment_base << 4) - 0xe0000, 0xffff,
|
||||
DT_CODE_READABLE, DPL_KERNEL);
|
||||
gGDT[APM_CODE16_SEGMENT >> 3].d_b = 0;
|
||||
// 16-bit segment
|
||||
|
||||
set_segment_descriptor(&gGDT[APM_DATA_SEGMENT >> 3],
|
||||
gBiosBase + (info.data_segment_base << 4) - 0xe0000, info.data_segment_length,
|
||||
DT_DATA_WRITEABLE, DPL_KERNEL);
|
||||
|
||||
// setup APM entry point
|
||||
|
||||
sAPMBiosEntry.segment = APM_CODE32_SEGMENT;
|
||||
sAPMBiosEntry.offset = info.code32_segment_offset;
|
||||
|
||||
apm_driver_version(info.version);
|
||||
|
||||
if (apm_enable_power_management(APM_ALL_DEVICES, true) != B_OK)
|
||||
dprintf("APM: cannot enable power management.\n");
|
||||
if (apm_engage_power_management(APM_ALL_DEVICES, true) != B_OK)
|
||||
dprintf("APM: cannot engage.\n");
|
||||
|
||||
register_kernel_daemon(apm_daemon, NULL, 10);
|
||||
// run the daemon once every second
|
||||
|
||||
//apm_set_state(APM_ALL_DEVICES, APM_POWER_STATE_OFF);
|
||||
panic("done");
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
@ -273,8 +273,7 @@ arch_cpu_init_post_vm(kernel_args *args)
|
||||
|
||||
// add TSS descriptor for this new TSS
|
||||
set_tss_descriptor(&gGDT[TSS_BASE_SEGMENT + i], (addr_t)sTSS[i], sizeof(struct tss));
|
||||
|
||||
|
||||
|
||||
// create double-fault task
|
||||
sprintf(tssName, "double_fault_tss%lu", i);
|
||||
area = create_area(tssName, (void **)&sDoubleFaultTSS[i], B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE,
|
||||
|
@ -1,20 +1,34 @@
|
||||
/*
|
||||
* Copyright 2006, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
* Copyright 2006, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Ingo Weinhold <bonefish@cs.tu-berlin.de>
|
||||
* Axel Dörfler, axeld@pinc-software.de
|
||||
*/
|
||||
|
||||
|
||||
#include <arch/platform.h>
|
||||
#include <apm.h>
|
||||
|
||||
|
||||
status_t
|
||||
arch_platform_init(struct kernel_args *kernelArgs)
|
||||
arch_platform_init(struct kernel_args *args)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_platform_init_post_vm(struct kernel_args *kernelArgs)
|
||||
arch_platform_init_post_vm(struct kernel_args *args)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_platform_init_post_thread(struct kernel_args *args)
|
||||
{
|
||||
return apm_init(args);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Copyright 2002-2006, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
||||
@ -33,6 +33,8 @@
|
||||
|
||||
#define kMaxMemoryTypeRegisters 32
|
||||
|
||||
void *gDmaAddress;
|
||||
|
||||
static uint32 sMemoryTypeBitmap;
|
||||
static int32 sMemoryTypeIDs[kMaxMemoryTypeRegisters];
|
||||
static int32 sMemoryTypeRegisterCount;
|
||||
@ -164,7 +166,6 @@ arch_vm_init(kernel_args *args)
|
||||
status_t
|
||||
arch_vm_init_post_area(kernel_args *args)
|
||||
{
|
||||
void *dmaAddress;
|
||||
area_id id;
|
||||
|
||||
TRACE(("arch_vm_init_post_area: entry\n"));
|
||||
@ -174,7 +175,8 @@ arch_vm_init_post_area(kernel_args *args)
|
||||
|
||||
// map 0 - 0xa0000 directly
|
||||
id = map_physical_memory("dma_region", (void *)0x0, 0xa0000,
|
||||
B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, &dmaAddress);
|
||||
B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
|
||||
&gDmaAddress);
|
||||
if (id < 0) {
|
||||
panic("arch_vm_init_post_area: unable to map dma region\n");
|
||||
return B_NO_MEMORY;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
* Copyright 2004-2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@ -54,7 +54,7 @@ enum {
|
||||
};
|
||||
|
||||
|
||||
static addr_t sBiosBase;
|
||||
addr_t gBiosBase;
|
||||
static addr_t sBios32ServiceDirectory;
|
||||
|
||||
|
||||
@ -121,17 +121,17 @@ bios_init(void)
|
||||
{
|
||||
// map BIOS area 0xe0000 - 0xfffff
|
||||
area_id biosArea = map_physical_memory("pc bios", (void *)0xe0000, 0x20000,
|
||||
B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&sBiosBase);
|
||||
B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&gBiosBase);
|
||||
if (biosArea < 0)
|
||||
return biosArea;
|
||||
|
||||
TRACE(("PC BIOS mapped to %p\n", (void *)sBiosBase));
|
||||
TRACE(("PC BIOS mapped to %p\n", (void *)gBiosBase));
|
||||
|
||||
// ToDo: add driver settings support to disable the services below
|
||||
|
||||
// search for available BIOS services
|
||||
|
||||
addr_t base = sBiosBase;
|
||||
addr_t base = gBiosBase;
|
||||
addr_t end = base + 0x20000;
|
||||
|
||||
while (base < end) {
|
||||
@ -145,7 +145,7 @@ bios_init(void)
|
||||
|
||||
if (bios32->service_directory >= 0xe0000
|
||||
&& bios32->service_directory <= 0xfffff)
|
||||
sBios32ServiceDirectory = sBiosBase - 0xe0000 + bios32->service_directory;
|
||||
sBios32ServiceDirectory = gBiosBase - 0xe0000 + bios32->service_directory;
|
||||
}
|
||||
break;
|
||||
case SMBIOS:
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
* Copyright 2002-2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||
@ -141,6 +141,7 @@ _start(kernel_args *bootKernelArgs, int currentCPU)
|
||||
port_init(&sKernelArgs);
|
||||
TRACE(("init kernel daemons\n"));
|
||||
kernel_daemon_init();
|
||||
arch_platform_init_post_thread(&sKernelArgs);
|
||||
|
||||
TRACE(("init VM threads\n"));
|
||||
vm_init_post_thread(&sKernelArgs);
|
||||
|
Loading…
Reference in New Issue
Block a user