Je crée un système d'exploitation en mode protégé basé sur l'architecture x86 d'Intel, et je cherchais des informations sur la façon d'éteindre l'ordinateur via le code d'assemblage, ou quelque chose comme ça. Pourriez-vous m'aider avec ce problème?Comment éteindre l'ordinateur d'un environnement autonome?
Répondre
de http://forum.osdev.org/viewtopic.php?t=16990
L'arrêt est techniquement une ACPI chose très simple tout ce qui est nécessaire est un outw (PM1a_CNT, SLP_TYPa | SLP_EN); et l'ordinateur est éteint. Le problème réside dans la collecte de ces valeurs d'autant plus que le SLP_TYPa est dans l'objet _S5 qui est dans le DSDT et donc codé AML.
Vous trouverez ci-dessous une simple "carte" d'où trouver ces champs.
"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.)
Pour exporter l'objet \_S5
on utilise normalement un interprète AML mais c'est évidemment pas une option étant donné que nous construisons un système d'exploitation de passe-temps. La solution simple est de scanner le DSDT manuellement. Le langage AML spécifie que les objets _... sont définis une seule fois ce qui rend très simple la recherche de l'objet \_S5
puisqu'un simple memcmp()
suffit. Une fois trouvées, les valeurs SLP_TYPx
sont extraites.
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
La collecte des informations est préférable d'effectuer lors de l'initialisation OS car après que vous pouvez réutiliser la RAM et ne pas besoin de se soucier de la corrompre.
Maintenant tout ce qui reste est outw(PM1a_CNT, SLP_TYPa | SLP_EN);
et vous êtes parti. Si PM1b_CNT != 0
vous devez le répéter avec b.
Si cela était un peu trop abstrait ici est un code à regarder
//
// 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");
}
Pour plus d'informations, lisez les sections correspondantes de la spécification 1.0a ACPI
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
Cela fonctionne sur tous mes machines bochs et qemu. mais j'ai remarqué que l'on n'a pas besoin d'activer ACPI pour que l'ordinateur s'éteigne. Bien que je ne sais pas si c'est toujours le cas.
Si vous voulez juste jouer un peu. Pour Bochs et qemu il est outw(0xB004, 0x0 | 0x2000);
APM méthode testée sur qemu-system-i386
2.0.0 Ubuntu 14.04:
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
Pour la compilation exacte et étapes en cours d'exécution sur QEMU, see this repo
articles osdev.org : http://wiki.osdev.org/Shutdown, http://wiki.osdev.org/APM
ACPI est la nouvelle méthode, meilleure.
- 1. Comment éteindre l'ordinateur?
- 2. Éteindre l'écran
- 3. Comment puis-je éteindre Windows?
- 4. Éteindre l'éclipse confirmer déplacer
- 5. Comment compiler autonome scala
- 6. Comment créer un programme C++ autonome?
- 7. Éteindre Cluster MongoDB Sharded proprement
- 8. "Éteindre" le flux de sortie
- 9. Logcat client autonome
- 10. Android - éteindre les lumières de touches matérielles
- 11. Eclipse IDE Code de formatage: éteindre indentation
- 12. Allumer/éteindre la lampe LED USB
- 13. Comment éteindre le GPS par programmation sur un Blackberry
- 14. Comment éteindre correctement l'alimentation du moniteur en C#?
- 15. éteindre le mode veille sur Kindle?
- 16. Éteindre une requête Servlet interne dans Tomcat
- 17. Comment séparer un environnement de développement d'un environnement de production
- 18. Comment créer un nouvel environnement Beamer avec un environnement verbatim?
- 19. application autonome en python
- 20. Exécuter Silverlight 3 autonome
- 21. Comment démarrer Quartz en mode autonome?
- 22. comment exécuter un test Capybara autonome?
- 23. Propel en tant que bibliothèque autonome
- 24. client WebService Java autonome
- 25. Comment réinitialiser mon environnement gem?
- 26. Comment puis-je environnement sudo?
- 27. Environnement CVSROOT
- 28. autonome page asp.net
- 29. autonome DataTable en .Net
- 30. Script ajax autonome
http://osdev.org est un endroit agréable à regarder ... Je n'ai jamais eu le code d'arrêt de travailler dans mon propre hobby OS si je ne peux pas donner une bonne réponse – Earlz
duplication possible de [Éteindre l'ordinateur en utilisant l'assembly] (http: // stackoverflow.com/questions/678458/shutdown-the-computer-using-assembly) ou très simmilar –
@Preet, pertinent mais je ne pense pas que ce soit un doublon exact. Cette question demande comment l'arrêter de votre propre système d'exploitation (ou un environnement autonome) où l'autre ne suppose pas que .. et @Carlos, quel mode de processeur êtes-vous? Mode réel, mode protégé ou mode long? (16bit, 32bit ou 64bit) – Earlz