增加ACPI驱动, 实现关机

This commit is contained in:
xiaoyi1212 2024-04-14 17:14:26 +08:00
parent a118bbec58
commit 099592cdc2
9 changed files with 541 additions and 11 deletions

View File

@ -52,7 +52,7 @@ ISR_NOERRCODE 31
; 通用中断处理程序
isr_common_stub:
pusha ; 存储所有寄存器
pusha
mov ax, ds
push eax ; 存储ds
@ -62,17 +62,17 @@ isr_common_stub:
mov es, ax
mov fs, ax
mov gs, ax
call isr_handler ; 调用C语言处理函数
pop eax ; 恢复各段
call isr_handler ; call isr_headler(registers_t reg);
pop eax ; 恢复
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
popa ; 弹出所有寄存器
popa
add esp, 8 ; 弹出错误码和中断ID
iret ; 从中断返回
iret
%macro IRQ 2
global irq%1

View File

@ -9,6 +9,7 @@ global tss_flush, gdt_flush, switch_to
section .text
switch_to:
mov eax, [esp+4]

278
driver/acpi.c Normal file
View File

@ -0,0 +1,278 @@
#include "../include/acpi.h"
#include "../include/memory.h"
#include "../include/graphics.h"
#include "../include/io.h"
#include "../include/isr.h"
#include "../include/timer.h"
uint16_t SLP_TYPa;
uint16_t SLP_TYPb;
uint32_t SMI_CMD;
uint8_t ACPI_ENABLE;
uint8_t ACPI_DISABLE;
uint32_t *PM1a_CNT;
uint32_t *PM1b_CNT;
uint8_t PM1_CNT_LEN;
uint16_t SLP_EN;
uint16_t SCI_EN;
acpi_rsdt_t *rsdt; // root system descript table
acpi_facp_t *facp; // fixed ACPI table
int acpi_enable() {
int i;
// check if enable ACPI
if (io_in16((uint32_t) PM1a_CNT) & SCI_EN) {
printf("ACPI already enable!\n");
return 0;
}
if (SMI_CMD && ACPI_ENABLE) {
// send ACPI_ENABLE cmd
io_out8((uint16_t)
SMI_CMD, ACPI_ENABLE);
// wait enable
for (i = 0; i < 300; i++) {
if (io_in16((uint32_t) PM1a_CNT) & SCI_EN) {
break;
}
clock_sleep(5);
}
// wait enable
if (PM1b_CNT) {
for (i = 0; i < 300; i++) {
if (io_in16((uint32_t) PM1b_CNT) & SCI_EN) {
break;
}
clock_sleep(5);
}
}
// check enable status
if (i < 300) {
printf("[acpi]: Enable ACPI\n");
return 0;
} else {
printf("Counld't enable ACPI\n");
return -1;
}
}
return -1;
}
int acpi_disable() {
int i;
if (!io_in16((uint16_t)PM1a_CNT) &SCI_EN)
return 0;
if (SMI_CMD || ACPI_DISABLE) {
io_out8((uint16_t)
SMI_CMD, ACPI_DISABLE);
for (i = 0; i < 300; i++) {
if (!io_in16((uint16_t)PM1a_CNT) &SCI_EN)
break;
clock_sleep(5);
}
for (i = 0; i < 300; i++) {
if (!io_in16((uint16_t)PM1b_CNT) &SCI_EN)
break;
clock_sleep(5);
}
if (i < 300) {
printf("ACPI Disable!\n");
return 0;
} else {
printf("Could't disable ACPI\n");
return -1;
}
}
return -1;
}
uint8_t *AcpiGetRSDPtr() {
uint32_t *addr;
uint32_t *rsdt;
uint32_t ebda;
for (addr = (uint32_t *) 0x000E0000; addr < (uint32_t *) 0x00100000; addr += 0x10 / sizeof(addr)) {
rsdt = AcpiCheckRSDPtr(addr);
if (rsdt) {
return rsdt;
}
}
// search extented bios data area for the root system description pointer signature
ebda = *(uint16_t * )
0x40E;
ebda = ebda * 0x10 & 0xfffff;
for (addr = (uint32_t *) ebda; addr < (uint32_t * )(ebda + 1024); addr += 0x10 / sizeof(addr)) {
rsdt = AcpiCheckRSDPtr(addr);
if (rsdt) {
return rsdt;
}
}
return NULL;
}
void power_reset() {
uint8_t val;
if (!SCI_EN)
return;
while (1) {
// write ICH port
io_out8(0x92, 0x01);
// send RESET_VAL
io_out8((uint32_t) facp->RESET_REG.address, facp->RESET_VALUE);
}
}
void power_off() {
if (!SCI_EN)
return;
while (1) {
printf("[acpi] send power off command!\n");
io_out16((uint32_t) PM1a_CNT, SLP_TYPa | SLP_EN);
if (!PM1b_CNT) {
io_out16((uint32_t) PM1b_CNT, SLP_TYPb | SLP_EN);
}
}
}
int AcpiCheckHeader(void *ptr, uint8_t *sign) {
uint8_t * bptr = ptr;
uint32_t len = *(bptr + 4);
uint8_t checksum = 0;
if (!memcmp(bptr, sign, 4)) {
while (len-- > 0) {
checksum += *bptr++;
}
return 0;
}
return -1;
}
uint8_t *AcpiCheckRSDPtr(void *ptr) {
char *sign = "RSD PTR ";
acpi_rsdptr_t *rsdp = ptr;
uint8_t * bptr = ptr;
uint32_t i = 0;
uint8_t check = 0;
// check signature
if (!memcmp(sign, bptr, 8)) {
printf("[acpi] rsdp found at %0x\n", bptr);
for (i = 0; i < sizeof(acpi_rsdptr_t); i++) {
check += *bptr;
bptr++;
}
if (!check) {
return (uint8_t * )
rsdp->rsdt;
}
}
return NULL;
}
uint32_t AcpiGetMadtBase() {
uint32_t entrys = rsdt->length - HEADER_SIZE / 4;
uint32_t **p = &(rsdt->entry);
acpi_madt_t *madt = NULL;
while (--entrys) {
if (!AcpiCheckHeader(*p, "APIC")) {
madt = (acpi_madt_t *) *p;
return madt;
}
p++;
}
return 0;
}
static int AcpiSysInit() {
uint32_t **p;
uint32_t entrys;
uint32_t dsdtlen;
rsdt = (acpi_rsdt_t *) AcpiGetRSDPtr();
if (!rsdt || AcpiCheckHeader(rsdt, "RSDT") < 0) {
printf("No ACPI\n");
return -1;
}
entrys = rsdt->length - HEADER_SIZE / 4;
p = &(rsdt->entry);
while (entrys--) {
if (!AcpiCheckHeader(*p, "FACP")) {
facp = (acpi_facp_t *) *p;
ACPI_ENABLE = facp->ACPI_ENABLE;
ACPI_DISABLE = facp->ACPI_DISABLE;
SMI_CMD = facp->SMI_CMD;
PM1a_CNT = facp->PM1a_CNT_BLK;
PM1b_CNT = facp->PM1b_CNT_BLK;
PM1_CNT_LEN = facp->PM1_CNT_LEN;
SLP_EN = 1 << 13;
SCI_EN = 1;
uint8_t * S5Addr;
uint32_t dsdtlen;
if (!AcpiCheckHeader(facp->DSDT, "DSDT")) {
S5Addr = &(facp->DSDT->definition_block);
dsdtlen = facp->DSDT->length - HEADER_SIZE;
while (dsdtlen--) {
if (!memcmp(S5Addr, "_S5_", 4)) {
break;
}
S5Addr++;
}
if (dsdtlen) {
// check valid \_S5
if (*(S5Addr - 1) == 0x08 || (*(S5Addr - 2) == 0x08 && *(S5Addr - 1) == '\\')) {
S5Addr += 5;
S5Addr += ((*S5Addr & 0xC0) >> 6) + 2;
if (*S5Addr == 0x0A) {
S5Addr++;
}
SLP_TYPa = *(S5Addr) << 10;
S5Addr++;
if (*S5Addr == 0x0A) {
S5Addr++;
}
SLP_TYPb = *(S5Addr) << 10;
S5Addr++;
} else {
printf("[acpi] \\_S5 parse error!\n");
}
} else {
printf("[acpi] \\_S5 not present!\n");
}
} else {
printf("[acpi] no found DSDT table\n");
}
return 0;
}
++p;
}
printf("[acpi] No valid FACP present\n");
}
void acpi_install() {
AcpiSysInit();
acpi_enable();
// power init
// AcpiPowerInit();
}

218
include/acpi.h Normal file
View File

@ -0,0 +1,218 @@
#ifndef CRASHPOWEROS_ACPI_H
#define CRASHPOWEROS_ACPI_H
#include <stdint.h>
#include <stddef.h>
#define HEADER_SIZE 36
#define ACPI_TABLE_RSDT ((void *)rsdt)
#define ACPI_TABLE_FACP ((void *)facp)
#pragma pack(push, 1)
typedef struct
{
uint8_t addressid;
uint8_t register_bitwidth;
uint8_t register_bitoffset;
uint8_t access_size;
uint64_t address;
} acpi_address_t;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct
{
uint8_t signature[8];
uint8_t checksum;
uint8_t oem_id[6];
uint8_t revision;
uint32_t rsdt;
} acpi_rsdptr_t;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct
{
uint8_t signature[4]; // signature "RSDT"
uint32_t length;
uint8_t revision;
uint8_t checksum;
uint8_t oem_id[6];
uint8_t oem_tableid[8];
uint32_t oem_revision;
uint32_t creator_id;
uint32_t creator_revision;
uint32_t *entry;
} acpi_rsdt_t;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct
{
uint8_t signature[4];
uint32_t length;
uint8_t revision;
uint8_t checksum;
uint8_t oem_id[6];
uint8_t oem_tableid[8];
uint32_t oem_revision;
uint32_t creator_id;
uint8_t definition_block;
} acpi_dsdt_t;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct
{
uint8_t signature[4];
uint32_t length;
uint8_t FADT_major_version;
uint8_t checksum;
uint8_t ome_id[6];
uint8_t oem_tableid[8];
uint32_t oem_revision;
uint32_t creator_id;
uint32_t creator_revision;
uint32_t FIRMWARE_CTRL;
acpi_dsdt_t *DSDT;
// no longer in use
uint8_t unused0;
uint8_t PM_profile;
uint16_t SCI_INT;
uint32_t SMI_CMD;
uint8_t ACPI_ENABLE;
uint8_t ACPI_DISABLE;
uint8_t S4BIOS_REQ;
uint8_t PSTATE_CNT;
uint32_t PM1a_EVT_BLK;
uint32_t PM1b_EVT_BLK;
uint32_t PM1a_CNT_BLK;
uint32_t PM1b_CNT_BLK;
uint32_t PM2_CNT_BLK;
uint32_t PM_TMR_BLK;
uint32_t GPE0_BLK;
uint32_t GPE1_BLK;
uint8_t PM1_EVT_LEN;
uint8_t PM1_CNT_LEN;
uint8_t PM2_CNT_LEN;
uint8_t PM_TMR_LEN;
uint8_t GPE0_BLK_LEN;
uint8_t GPE1_BLK_LEN;
uint8_t GPE1_BASE;
uint8_t CST_CNT;
uint16_t P_LVL2_LAT;
uint16_t P_LVL3_LAT;
uint16_t FLUSH_SIZE;
uint16_t FLUSH_STRIDE;
uint8_t DUTY_OFFSET;
uint8_t DUTY_WIDTH;
uint8_t DAY_ALRM;
uint8_t MON_ALRM;
uint8_t CENTURY;
// reserved in ACPI 1.0,used in since ACPI 2.0+
uint16_t IAPC_BOOT_ARCH;
uint8_t unused1;
uint32_t flags;
acpi_address_t RESET_REG;
uint8_t RESET_VALUE;
uint16_t ARM_BOOT_ARCH;
uint8_t FADT_minjor_version;
// there used in 64bits address mode
uint64_t *X_FIREWARE_CTRL;
uint64_t *X_DSDT;
acpi_address_t X_PM1a_EVT_BLK;
acpi_address_t X_PM1b_EVT_BLK;
acpi_address_t X_PM1a_CNT_BLK;
acpi_address_t X_PM1b_CNT_BLK;
acpi_address_t X_PM2_CNT_BLK;
acpi_address_t X_PM_TMR_BLK;
acpi_address_t X_GPE0_BLK;
acpi_address_t X_GPE1_BLK;
acpi_address_t SLEEP_CONTROL_REG;
acpi_address_t SLEEP_STATUS_REG;
uint8_t hypervisor_vendor_id;
} acpi_facp_t;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct
{
uint8_t sign[4]; // string 'APIC'
uint32_t len;
uint8_t revision;
uint8_t chksum;
uint8_t oemid[6];
uint8_t oemtableid[8];
uint8_t oemrevision[4];
uint8_t create_id[4];
uint8_t create_revision[4];
uint32_t local_apic; // local apic address
uint32_t flags; // flags =1 install DUAL PIC hardware
} acpi_madt_t;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct
{
uint8_t ioapic_id;
uint8_t reserved;
uint32_t ioapic_base; // iobase base
uint32_t gsi_base;
} madt_ioapic_entry_t;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct
{
uint8_t bus;
uint8_t irq;
uint32_t gsi;
uint16_t flags;
} madt_ioapic_int_assert_t;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct
{
uint8_t nmi;
uint8_t reserved;
uint16_t flags;
uint32_t gsi;
} madt_ioapic_nmi_assert_t;
#pragma pack(pop)
typedef enum
{
MADT_PROCESSOR_LOCAL_APIC = 0,
MADT_PRCESSOR_IOAPIC = 1,
MADT_LOCAL_INT_ASSERT = 2,
MADT_LOCAL_NMI_ASSERT = 3,
} madt_entry_t;
#pragma pack(push, 1)
typedef struct
{
uint8_t ACPI_processorID;
uint8_t APIC_ID;
uint32_t flags; // bit0 = processor enabled bit1 = online capable
} madt_processor_localAPIC_t;
#pragma pack(pop)
uint8_t *AcpiGetRSDPtr();
int AcpiCheckHeader(void *ptr, uint8_t *sign);
uint8_t *AcpiCheckRSDPtr(void *ptr);
uint32_t AcpiGetMadtBase();
void power_off();
void power_reset();
int acpi_enable();
int acpi_disable();
void acpi_install();
#endif //CRASHPOWEROS_ACPI_H

View File

@ -18,5 +18,6 @@ void cmd_mkdir(int argc, char **argv);
void cmd_read(int argc, char **argv);
void cmd_cat(int argc, char **argv);
void cmd_ls();
void cmd_shutdown();
#endif //CRASHPOWEROS_SHELL_H

View File

@ -28,7 +28,7 @@ struct task_struct {
char *name; // 进程名
void *stack; // 进程的内核栈地址
page_directory_t *pgd_dir; // 进程页表
struct context context; // 进程切换需要的上下文信息
struct context context; // 上下文信息
struct task_struct *next; // 链表指针
};
@ -46,4 +46,6 @@ void change_task_to(struct task_struct *next);
void task_kill(int pid);
void kill_all_task();
#endif //CRASHPOWEROS_TASK_H

View File

@ -10,19 +10,24 @@
#include "../include/keyboard.h"
#include "../include/shell.h"
#include "../include/date.h"
#include "../include/acpi.h"
extern uint32_t end;
extern int status;
uint32_t placement_address = (uint32_t) & end;
void reset_kernel(){
printf("Restart %s for x86...",OS_NAME);
printf("Restart %s for x86...\n",OS_NAME);
kill_all_task();
clock_sleep(10);
outb(0x64,0xfe);
power_reset();
}
void shutdown_kernel(){
//TODO ACPI Driver
printf("Shutdown %s for x86...\n",OS_NAME);
kill_all_task();
clock_sleep(10);
power_off();
}
void kernel_main(multiboot_t *multiboot) {
@ -40,10 +45,12 @@ void kernel_main(multiboot_t *multiboot) {
idt_install();
printf("[\035kernel\036]: description table config success!\n");
init_timer(10);
acpi_install();
printf("[\035kernel\036]: ACPI enable success!\n");
init_page();
printf("[\035kernel\036]: page set success!\n");
init_sched();
printf("[\035kernel\036]: PCB load success!\n");
printf("[\035kernel\036]: task load success!\n");
init_keyboard();
printf("[\035kernel\036]: Keyboard driver load success!\n");

View File

@ -1,6 +1,7 @@
#include "../include/task.h"
#include "../include/common.h"
#include "../include/graphics.h"
#include "../include/io.h"
struct task_struct *running_proc_head = NULL;
struct task_struct *wait_proc_head = NULL;
@ -111,7 +112,8 @@ void task_kill(int pid){
break;
}
printf("Task [%s] exit code: -130.\n",argv->name);
io_sti();
kfree(argv);
struct task_struct *head = running_proc_head;
struct task_struct *last = NULL;
while (1){
@ -122,6 +124,7 @@ void task_kill(int pid){
last = head;
head = head->next;
}
io_cli();
}
void schedule() {
@ -137,6 +140,7 @@ void change_task_to(struct task_struct *next) {
//switch_page_directory(current->pgd_dir);
switch_to(&(prev->context), &(current->context));
}
}
@ -185,6 +189,18 @@ void kthread_exit() {
while (1);
}
void kill_all_task(){
struct task_struct *head = running_proc_head;
while (1){
head = head->next;
if(head == NULL || head->pid == running_proc_head->pid){
return;
}
if(head->pid == current->pid) continue;
task_kill(head->pid);
}
}
void init_sched() {
// 为当前执行流创建信息结构体 该结构位于当前执行流的栈最低端
current = (struct task_struct *) kmalloc(sizeof(struct task_struct));

View File

@ -184,6 +184,10 @@ void cmd_reset(){
reset_kernel();
}
void cmd_shutdown(){
shutdown_kernel();
}
void setup_shell(){
vga_clear();
printf("%s for x86 [Version %s] \n",OS_NAME, OS_VERSION);
@ -225,6 +229,8 @@ void setup_shell(){
cmd_del(argc, argv);
else if (!strcmp("reset", argv[0]))
cmd_reset();
else if (!strcmp("shutdown", argv[0])||!strcmp("exit", argv[0]))
cmd_shutdown();
else if (!strcmp("help", argv[0]) || !strcmp("?", argv[0]) || !strcmp("h", argv[0])) {
vga_writestring("-=[\037CrashPowerShell Helper\036]=-\n");
vga_writestring("help ? h \032Print shell help info.\036\n");
@ -238,6 +244,7 @@ void setup_shell(){
vga_writestring("sysinfo \032Print system info.\036\n");
vga_writestring("proc [kill<pid>|list] \032Lists all running processes.\036\n");
vga_writestring("reset \032Reset OS.\036\n");
vga_writestring("shutdown exit \032Shutdown OS.\036\n");
} else printf("\033[Shell]: Unknown command '%s'.\036\n", argv[0]);
}
}