2010-06-29 13 views
13

मैं इंटेल के x86 आर्किटेक्चर के आधार पर एक संरक्षित-मोड ओएस बना रहा हूं, और इस बारे में कुछ जानकारी ढूंढ रहा था कि कंप्यूटर को असेंबली कोड, या ऐसा कुछ कैसे करें। क्या आप इस समस्या में मेरी सहायता करेंगे?एक फ्रीस्टैंडिंग पर्यावरण से कंप्यूटर को कैसे पावर करें?

+3

http://osdev.org देखने के लिए एक अच्छी जगह है ... मुझे अपने खुद के शौक ओएस में काम करने के लिए शटडाउन कोड कभी नहीं मिला है, इसलिए मैं एक अच्छा जवाब नहीं दे सकता – Earlz

+1

संभावित डुप्लिकेट [कंप्यूटर को बंद करें असेंबली का उपयोग] [http: // stackoverflow।कॉम/प्रश्न/678458/शटडाउन-द-कंप्यूटर-उपयोग-असेंबली) या बहुत ही समान –

+2

@ कृपया, प्रासंगिक लेकिन मुझे नहीं लगता कि यह एक सटीक डुप्लिकेट है। यह सवाल पूछता है कि इसे अपने ओएस (या एक फ्रीस्टैंडिंग पर्यावरण) से बंद करने के लिए कैसे प्राप्त करें, जहां दूसरा यह नहीं मानता .. और @ कार्लोस, आप किस प्रोसेसर मोड में हैं? रीयल-मोड, संरक्षित-मोड, या लंबी-मोड? (16 बिट, 32 बिट, या 64 बिट) – Earlz

उत्तर

8
से http://forum.osdev.org/viewtopic.php?t=16990

ACPI बंद तकनीकी रूप से एक बहुत आसान बात की आवश्यकता होती है एक outw (PM1a_CNT, SLP_TYPa | SLP_EN) है, और कंप्यूटर बंद है। समस्या इन मानों को इकट्ठा करने में निहित है, खासकर जब से SLP_TYPa _S5 ऑब्जेक्ट में है जो डीएसडीटी में है और इसलिए एएमएल एन्कोड किया गया है।

नीचे इन फ़ील्ड को खोजने के लिए एक सरल "मानचित्र" है।

 
    "RSD PTR " 
     || 
    RsdtAddress pointer at offset 16 
     || 
     \/ 
    "RSDT" 
     || 
    pointer at offset 36 + 4 * n (check the target for the sig "FACP" to get the right n) 
     || 
     \/ 
    "FACP" 
     || 
     ||=====\ 
     || || 
     || PM1a_CNT_BLK; offset: 64 (see section 4.7.3.2) 
     || PM1b_CNT_BLK; offset: 68 
     ||  || 
     ||  \/ 
     ||  SLP_TYPx; bit 10-12 
     ||  SLP_EN;  bit 13 
     || 
    DSDT pointer at offset 40 
     || 
     \/ 
    "DSDT" (export the \_S5 object somehow.) 

\_S5 वस्तु एक सामान्य रूप से एक एएमएल दुभाषिया का प्रयोग करेंगे निर्यात करने के लिए, लेकिन यह स्पष्ट रूप से हम एक शौक ओएस का निर्माण कर रहे पर विचार के लिए एक विकल्प नहीं है। सरल समाधान डीएसडीटी को मैन्युअल रूप से स्कैन करना है। एएमएल भाषा निर्दिष्ट करती है कि _... वस्तुओं को केवल एक बार परिभाषित किया जाता है जो \_S5 ऑब्जेक्ट को खोजने के लिए बहुत आसान बनाता है क्योंकि एक सरल memcmp() पर्याप्त है। एक बार पाया गया कि SLP_TYPx मान निकाले गए हैं। क्योंकि के बाद कि आप राम का पुन: उपयोग कर सकते हैं और यह भ्रष्ट बारे में चिंता करने की जरूरत नहीं है

 
    bytecode of the \_S5 object 
    ----------------------------------------- 
      | (optional) | | | | 
    NameOP | \   | _ | S | 5 | _ 
    08  | 5A   | 5F | 53 | 35 | 5F 

    ----------------------------------------------------------------------------------------------------------- 
       |   |    | (SLP_TYPa ) | (SLP_TYPb ) | (Reserved ) | (Reserved ) 
    PackageOP | PkgLength | NumElements | byteprefix Num | byteprefix Num | byteprefix Num | byteprefix Num 
    12  | 0A  | 04   | 0A   05 | 0A   05 | 0A   05 | 0A   05 

    ----this-structure-was-also-seen---------------------- 
    PackageOP | PkgLength | NumElements | 
    12  | 06  | 04   | 00 00 00 00 

जानकारी की भीड़ सबसे अच्छा ओएस प्रारंभ में किया जाता है।

अब यह सब बनी हुई है outw(PM1a_CNT, SLP_TYPa | SLP_EN); और आप चले गए हैं। यदि PM1b_CNT != 0 आपको इसे बी के साथ दोहराना होगा।

हैं कि एक छोटे से यहाँ भी सार कुछ कोड

// 
// here is the slighlty complicated ACPI poweroff code 
// 

#include <stddef.h> 
#include <print.h> 
#include <string.h> 
#include <io.h> 
#include <time.h> 



dword *SMI_CMD; 
byte ACPI_ENABLE; 
byte ACPI_DISABLE; 
dword *PM1a_CNT; 
dword *PM1b_CNT; 
word SLP_TYPa; 
word SLP_TYPb; 
word SLP_EN; 
word SCI_EN; 
byte PM1_CNT_LEN; 



struct RSDPtr 
{ 
    byte Signature[8]; 
    byte CheckSum; 
    byte OemID[6]; 
    byte Revision; 
    dword *RsdtAddress; 
}; 



struct FACP 
{ 
    byte Signature[4]; 
    dword Length; 
    byte unneded1[40 - 8]; 
    dword *DSDT; 
    byte unneded2[48 - 44]; 
    dword *SMI_CMD; 
    byte ACPI_ENABLE; 
    byte ACPI_DISABLE; 
    byte unneded3[64 - 54]; 
    dword *PM1a_CNT_BLK; 
    dword *PM1b_CNT_BLK; 
    byte unneded4[89 - 72]; 
    byte PM1_CNT_LEN; 
}; 



// check if the given address has a valid header 
unsigned int *acpiCheckRSDPtr(unsigned int *ptr) 
{ 
    char *sig = "RSD PTR "; 
    struct RSDPtr *rsdp = (struct RSDPtr *) ptr; 
    byte *bptr; 
    byte check = 0; 
    int i; 

    if (memcmp(sig, rsdp, 8) == 0) 
    { 
     // check checksum rsdpd 
     bptr = (byte *) ptr; 
     for (i=0; i<sizeof(struct RSDPtr); i++) 
     { 
     check += *bptr; 
     bptr++; 
     } 

     // found valid rsdpd 
     if (check == 0) { 
     /* 
      if (desc->Revision == 0) 
      wrstr("acpi 1"); 
     else 
      wrstr("acpi 2"); 
     */ 
     return (unsigned int *) rsdp->RsdtAddress; 
     } 
    } 

    return NULL; 
} 



// finds the acpi header and returns the address of the rsdt 
unsigned int *acpiGetRSDPtr(void) 
{ 
    unsigned int *addr; 
    unsigned int *rsdp; 

    // search below the 1mb mark for RSDP signature 
    for (addr = (unsigned int *) 0x000E0000; (int) addr<0x00100000; addr += 0x10/sizeof(addr)) 
    { 
     rsdp = acpiCheckRSDPtr(addr); 
     if (rsdp != NULL) 
     return rsdp; 
    } 


    // at address 0x40:0x0E is the RM segment of the ebda 
    int ebda = *((short *) 0x40E); // get pointer 
    ebda = ebda*0x10 &0x000FFFFF; // transform segment into linear address 

    // search Extended BIOS Data Area for the Root System Description Pointer signature 
    for (addr = (unsigned int *) ebda; (int) addr<ebda+1024; addr+= 0x10/sizeof(addr)) 
    { 
     rsdp = acpiCheckRSDPtr(addr); 
     if (rsdp != NULL) 
     return rsdp; 
    } 

    return NULL; 
} 



// checks for a given header and validates checksum 
int acpiCheckHeader(unsigned int *ptr, char *sig) 
{ 
    if (memcmp(ptr, sig, 4) == 0) 
    { 
     char *checkPtr = (char *) ptr; 
     int len = *(ptr + 1); 
     char check = 0; 
     while (0<len--) 
     { 
     check += *checkPtr; 
     checkPtr++; 
     } 
     if (check == 0) 
     return 0; 
    } 
    return -1; 
} 



int acpiEnable(void) 
{ 
    // check if acpi is enabled 
    if ((inw((unsigned int) PM1a_CNT) &SCI_EN) == 0) 
    { 
     // check if acpi can be enabled 
     if (SMI_CMD != 0 && ACPI_ENABLE != 0) 
     { 
     outb((unsigned int) SMI_CMD, ACPI_ENABLE); // send acpi enable command 
     // give 3 seconds time to enable acpi 
     int i; 
     for (i=0; i<300; i++) 
     { 
      if ((inw((unsigned int) PM1a_CNT) &SCI_EN) == 1) 
       break; 
      sleep(10); 
     } 
     if (PM1b_CNT != 0) 
      for (; i<300; i++) 
      { 
       if ((inw((unsigned int) PM1b_CNT) &SCI_EN) == 1) 
        break; 
       sleep(10); 
      } 
     if (i<300) { 
      wrstr("enabled acpi.\n"); 
      return 0; 
     } else { 
      wrstr("couldn't enable acpi.\n"); 
      return -1; 
     } 
     } else { 
     wrstr("no known way to enable acpi.\n"); 
     return -1; 
     } 
    } else { 
     //wrstr("acpi was already enabled.\n"); 
     return 0; 
    } 
} 

// 
// bytecode of the \_S5 object 
// ----------------------------------------- 
//  | (optional) | | | | 
// NameOP | \   | _ | S | 5 | _ 
// 08  | 5A   | 5F | 53 | 35 | 5F 
// 
// ----------------------------------------------------------------------------------------------------------- 
//   |   |    | (SLP_TYPa ) | (SLP_TYPb ) | (Reserved ) | (Reserved ) 
// PackageOP | PkgLength | NumElements | byteprefix Num | byteprefix Num | byteprefix Num | byteprefix Num 
// 12  | 0A  | 04   | 0A   05 | 0A   05 | 0A   05 | 0A   05 
// 
//----this-structure-was-also-seen---------------------- 
// PackageOP | PkgLength | NumElements | 
// 12  | 06  | 04   | 00 00 00 00 
// 
// (Pkglength bit 6-7 encode additional PkgLength bytes [shouldn't be the case here]) 
// 
int initAcpi(void) 
{ 
    unsigned int *ptr = acpiGetRSDPtr(); 

    // check if address is correct (if acpi is available on this pc) 
    if (ptr != NULL && acpiCheckHeader(ptr, "RSDT") == 0) 
    { 
     // the RSDT contains an unknown number of pointers to acpi tables 
     int entrys = *(ptr + 1); 
     entrys = (entrys-36) /4; 
     ptr += 36/4; // skip header information 

     while (0<entrys--) 
     { 
     // check if the desired table is reached 
     if (acpiCheckHeader((unsigned int *) *ptr, "FACP") == 0) 
     { 
      entrys = -2; 
      struct FACP *facp = (struct FACP *) *ptr; 
      if (acpiCheckHeader((unsigned int *) facp->DSDT, "DSDT") == 0) 
      { 
       // search the \_S5 package in the DSDT 
       char *S5Addr = (char *) facp->DSDT +36; // skip header 
       int dsdtLength = *(facp->DSDT+1) -36; 
       while (0 < dsdtLength--) 
       { 
        if (memcmp(S5Addr, "_S5_", 4) == 0) 
        break; 
        S5Addr++; 
       } 
       // check if \_S5 was found 
       if (dsdtLength > 0) 
       { 
        // check for valid AML structure 
        if ((*(S5Addr-1) == 0x08 || (*(S5Addr-2) == 0x08 && *(S5Addr-1) == '\\')) && *(S5Addr+4) == 0x12) 
        { 
        S5Addr += 5; 
        S5Addr += ((*S5Addr &0xC0)>>6) +2; // calculate PkgLength size 

        if (*S5Addr == 0x0A) 
         S5Addr++; // skip byteprefix 
        SLP_TYPa = *(S5Addr)<<10; 
        S5Addr++; 

        if (*S5Addr == 0x0A) 
         S5Addr++; // skip byteprefix 
        SLP_TYPb = *(S5Addr)<<10; 

        SMI_CMD = facp->SMI_CMD; 

        ACPI_ENABLE = facp->ACPI_ENABLE; 
        ACPI_DISABLE = facp->ACPI_DISABLE; 

        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; 

        return 0; 
        } else { 
        wrstr("\\_S5 parse error.\n"); 
        } 
       } else { 
        wrstr("\\_S5 not present.\n"); 
       } 
      } else { 
       wrstr("DSDT invalid.\n"); 
      } 
     } 
     ptr++; 
     } 
     wrstr("no valid FACP present.\n"); 
    } else { 
     wrstr("no acpi.\n"); 
    } 

    return -1; 
} 



void acpiPowerOff(void) 
{ 
    // SCI_EN is set to 1 if acpi shutdown is possible 
    if (SCI_EN == 0) 
     return; 

    acpiEnable(); 

    // send the shutdown command 
    outw((unsigned int) PM1a_CNT, SLP_TYPa | SLP_EN); 
    if (PM1b_CNT != 0) 
     outw((unsigned int) PM1b_CNT, SLP_TYPb | SLP_EN); 

    wrstr("acpi poweroff failed.\n"); 
} 

को देखने के लिए अधिक जानकारी के लिए ACPI 1.0a विनिर्देश

 
    9.1.7 Transitioning from the Working to the Soft Off State 
    7.5.2 \_Sx states 
    7.4.1 \_S5 
    4.7.2.3 Sleeping/Wake Control 

    16.3 AML Byte Streeam Byte Values 
    16.2.3 Package Length Encoding 

यह के सभी पर काम करता है की इसी वर्गों पढ़ा है था मेरी मशीन बोच और क्यूमु। लेकिन मैंने देखा कि पीसी को बिजली के लिए एसीपीआई सक्षम करने की आवश्यकता नहीं है। हालांकि मुझे नहीं पता कि यह हमेशा मामला है या नहीं।

यदि आप बस थोड़ा खेलना चाहते हैं। Bochs के लिए और उस पर qemu-system-i386 2.0.0 Ubuntu 14.04 परीक्षण किया outw(0xB004, 0x0 | 0x2000);

0

APM विधि है QEMU:

mov $0x5301, %ax 
xor %bx, %bx 
int $0x15 

/* Try to set apm version (to 1.2). */ 
mov $0x530e, %ax 
xor %bx, %bx 
mov $0x0102, %cx 
int $0x15 

/* Turn off the system. */ 
mov $0x5307, %ax 
mov $0x0001, %bx 
mov $0x0003, %cx 
int $0x15 

सटीक संकलन और QEMU पर चल रहे चरणों के लिए, see this repo

osdev.org लेख : http://wiki.osdev.org/Shutdown, http://wiki.osdev.org/APM

ACPI नई, बेहतर विधि है।

संबंधित मुद्दे