Update ACPI to implement shutdown

This commit is contained in:
Baptiste Wicht 2013-12-08 22:12:34 +01:00
parent 03e21e8b37
commit 92fa122b0f
8 changed files with 174 additions and 49 deletions

View File

@ -10,7 +10,7 @@
namespace acpi {
void init();
bool init();
void shutdown();
} //end of acpi namespace

View File

@ -14,8 +14,11 @@ namespace paging {
const int PAGE_SIZE = 4096;
bool identity_map(void* physical);
bool identity_map(void* physical, size_t pages);
void* physical_address(void* virt);
bool page_present(void* virt);
bool page_free_or_set(void* virt, void* physical);
bool identity_map(void* virt);
bool identity_map(void* virt, size_t pages);
} //end of namespace paging

View File

@ -25,6 +25,8 @@ uint64_t str_len(const char* a);
const char* str_until(char* a, char c);
const char* str_from(char* a, char c);
void memset(void * ptr, uint8_t value, size_t num);
template<typename T>
void memcopy(T* destination, const T* source, size_t size){
--source;

View File

@ -15,37 +15,39 @@
namespace {
uint32_t *SMI_CMD;
uint32_t SMI_CMD; //ptr
uint8_t ACPI_ENABLE;
uint8_t ACPI_DISABLE;
uint32_t *PM1a_CNT;
uint32_t *PM1b_CNT;
uint32_t PM1a_CNT; //ptr
uint32_t PM1b_CNT; //ptr
uint16_t SLP_TYPa;
uint16_t SLP_TYPb;
uint16_t SLP_EN;
uint16_t SCI_EN;
uint8_t PM1_CNT_LEN;
bool version_2 = false;
struct RSDPtr {
uint8_t Signature[8];
uint8_t CheckSum;
uint8_t OemID[6];
uint8_t Revision;
uint32_t *RsdtAddress;
uint32_t RsdtAddress; //ptr
};
struct FACP {
uint8_t Signature[4];
uint32_t Length;
uint8_t unneded1[40 - 8];
uint32_t *DSDT;
uint32_t DSDT; //ptr
uint8_t unneded2[48 - 44];
uint32_t *SMI_CMD;
uint32_t SMI_CMD; //ptr
uint8_t ACPI_ENABLE;
uint8_t ACPI_DISABLE;
uint8_t unneded3[64 - 54];
uint32_t *PM1a_CNT_BLK;
uint32_t *PM1b_CNT_BLK;
uint32_t PM1a_CNT_BLK; //ptr
uint32_t PM1b_CNT_BLK; //ptr
uint8_t unneded4[89 - 72];
uint8_t PM1_CNT_LEN;
};
@ -83,10 +85,8 @@ unsigned int* check_rsd_ptr(unsigned int *ptr) {
// found valid rsdpd
if (check == 0) {
if (rsdp->Revision == 0)
k_print_line("ACPI 1");
else
k_print_line("ACPI 2");
version_2 = rsdp->Revision != 0;
return reinterpret_cast<unsigned int *>(rsdp->RsdtAddress);
}
}
@ -142,14 +142,14 @@ int check_header(unsigned int *ptr, const char* sig){
int acpiEnable(void){
// check if acpi is enabled
if ( (in_word(reinterpret_cast<uint64_t>(PM1a_CNT)) &SCI_EN) == 0 ){
if ( (in_word(PM1a_CNT) &SCI_EN) == 0 ){
// check if acpi can be enabled
if (SMI_CMD != 0 && ACPI_ENABLE != 0){
out_byte(reinterpret_cast<uint64_t>(SMI_CMD), ACPI_ENABLE); // send acpi enable command
out_byte(SMI_CMD, ACPI_ENABLE); // send acpi enable command
// give 3 seconds time to enable acpi
int i;
for (i=0; i<300; i++ ){
if ( (in_word(reinterpret_cast<uint64_t>(PM1a_CNT)) & SCI_EN) == 1 )
if ( (in_word(PM1a_CNT) & SCI_EN) == 1 )
break;
sleep_ms(10);
}
@ -157,7 +157,7 @@ int acpiEnable(void){
if (PM1b_CNT != 0)
for (; i<300; i++ )
{
if ( (in_word(reinterpret_cast<uint64_t>(PM1b_CNT)) & SCI_EN) == 1 )
if ( (in_word(PM1b_CNT) & SCI_EN) == 1 )
break;
sleep_ms(10);
}
@ -199,17 +199,12 @@ int acpiEnable(void){
int init_acpi(){
unsigned int *ptr = get_rsd_ptr();
k_printf("%h\n", reinterpret_cast<uintptr_t>(ptr));
if(!paging::identity_map(ptr, 16)){
k_print_line("Impossible to map the ACPI tables");
return -1;
}
// check if address is correct ( if acpi is available on this pc )
if (ptr && check_header(ptr, "RSDT") == 0){
//k_print_line("2");
// the RSDT contains an unknown number of pointers to acpi tables
int entrys = *(ptr + 1);
entrys = (entrys-36) /4;
@ -220,11 +215,12 @@ int init_acpi(){
if (check_header(reinterpret_cast<unsigned int*>(*ptr), "FACP") == 0){
entrys = -2;
struct FACP *facp = reinterpret_cast<FACP*>(*ptr);
struct FACP* facp = reinterpret_cast<FACP*>(*ptr);
if (check_header(reinterpret_cast<unsigned int*>(facp->DSDT), "DSDT") == 0){
// search the \_S5 package in the DSDT
char *S5Addr = reinterpret_cast<char *>(facp->DSDT + 36); // skip header
int dsdtLength = *(facp->DSDT+1) -36;
int dsdtLength = *(reinterpret_cast<uint32_t*>(static_cast<uintptr_t>(facp->DSDT)+1)) - 36;
while (0 < dsdtLength--){
if ( memcmp(S5Addr, "_S5_", 4) == 0)
break;
@ -287,8 +283,8 @@ int init_acpi(){
} //end of anonymous namespace
void acpi::init(){
init_acpi();
bool acpi::init(){
return init_acpi() == 0;
}
void acpi::shutdown(){
@ -300,9 +296,9 @@ void acpi::shutdown(){
acpiEnable();
// send the shutdown command
out_word(reinterpret_cast<uint64_t>(PM1a_CNT), SLP_TYPa | SLP_EN );
out_word(PM1a_CNT, SLP_TYPa | SLP_EN );
if ( PM1b_CNT != 0 ){
out_word(reinterpret_cast<uint64_t>(PM1b_CNT), SLP_TYPb | SLP_EN );
out_word(PM1b_CNT, SLP_TYPb | SLP_EN );
}
k_print_line("acpi poweroff failed.");

View File

@ -7,6 +7,9 @@
#include "paging.hpp"
#include "types.hpp"
#include "utils.hpp"
#include "console.hpp"
namespace {
@ -16,44 +19,153 @@ typedef pt_t* pdt_t;
typedef pdt_t* pdpt_t;
typedef pdpt_t* pml4t_t;
constexpr int PRESENT = 0x1;
constexpr int WRITEABLE = 0x2;
constexpr int USER = 0x4;
//Memory from 0x70000 can be used for pages
uintptr_t last_page = 0x73000;
uintptr_t init_new_page(){
auto new_page = last_page + paging::PAGE_SIZE;
memset(reinterpret_cast<void*>(new_page), 0, paging::PAGE_SIZE);
last_page = new_page;
return new_page;
}
constexpr bool page_aligned(void* addr){
return !(reinterpret_cast<uintptr_t>(addr) & (paging::PAGE_SIZE - 1));
}
} //end of anonymous namespace
bool paging::identity_map(void* physical){
void* paging::physical_address(void* virt){
if(!page_present(virt)){
//TODO Not a very good value since 0x0 is a valid physical address
return nullptr;
}
//Find the correct indexes inside the paging table for the physical address
auto table = (reinterpret_cast<uintptr_t>(virt) >> 12) & 0x1FF;
auto directory = (reinterpret_cast<uintptr_t>(virt) >> 21) & 0x1FF;
auto directory_ptr = (reinterpret_cast<uintptr_t>(virt) >> 30) & 0x1FF;
auto pml4 = (reinterpret_cast<uintptr_t>(virt) >> 39) & 0x1FF;
pml4t_t pml4t = reinterpret_cast<pml4t_t>(0x70000);
auto pdpt = reinterpret_cast<pdpt_t>(reinterpret_cast<uintptr_t>(pml4t[pml4]) & ~0xFFF);
auto pdt = reinterpret_cast<pdt_t>(reinterpret_cast<uintptr_t>(pdpt[directory_ptr]) & ~0xFFF);
auto pt = reinterpret_cast<pt_t>(reinterpret_cast<uintptr_t>(pdt[directory]) & ~0xFFF);
return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(pt[table]) & ~0xFFF);
}
bool paging::page_present(void* virt){
//Find the correct indexes inside the paging table for the physical address
auto table = (reinterpret_cast<uintptr_t>(virt) >> 12) & 0x1FF;
auto directory = (reinterpret_cast<uintptr_t>(virt) >> 21) & 0x1FF;
auto directory_ptr = (reinterpret_cast<uintptr_t>(virt) >> 30) & 0x1FF;
auto pml4 = (reinterpret_cast<uintptr_t>(virt) >> 39) & 0x1FF;
pml4t_t pml4t = reinterpret_cast<pml4t_t>(0x70000);
if(!(reinterpret_cast<uintptr_t>(pml4t[pml4]) & PRESENT)){
return false;
}
auto pdpt = reinterpret_cast<pdpt_t>(reinterpret_cast<uintptr_t>(pml4t[pml4]) & ~0xFFF);
if(!(reinterpret_cast<uintptr_t>(pdpt[directory_ptr]) & PRESENT)){
return false;
}
auto pdt = reinterpret_cast<pdt_t>(reinterpret_cast<uintptr_t>(pdpt[directory_ptr]) & ~0xFFF);
if(!(reinterpret_cast<uintptr_t>(pdt[directory]) & PRESENT)){
return false;
}
auto pt = reinterpret_cast<pt_t>(reinterpret_cast<uintptr_t>(pdt[directory]) & ~0xFFF);
return reinterpret_cast<uintptr_t>(pt[table]) & PRESENT;
}
bool paging::page_free_or_set(void* virt, void* physical){
if(!page_present(virt)){
return true;
}
if(physical_address(virt) == physical){
return true;
}
return false;
}
bool paging::identity_map(void* virt){
//The address must be page-aligned
if(reinterpret_cast<uintptr_t>(physical) % PAGE_SIZE != 0){
if(!page_aligned(virt)){
return false;
}
//Find the correct indexes inside the paging table for the physical address
auto table = (reinterpret_cast<uintptr_t>(physical) >> 12) & 0x1FF;
auto directory = (reinterpret_cast<uintptr_t>(physical) >> 21) & 0x1FF;
auto directory_ptr = (reinterpret_cast<uintptr_t>(physical) >> 30) & 0x1FF;
auto pml4 = (reinterpret_cast<uintptr_t>(physical) >> 39) & 0x1FF;
auto table = (reinterpret_cast<uintptr_t>(virt) >> 12) & 0x1FF;
auto directory = (reinterpret_cast<uintptr_t>(virt) >> 21) & 0x1FF;
auto directory_ptr = (reinterpret_cast<uintptr_t>(virt) >> 30) & 0x1FF;
auto pml4 = (reinterpret_cast<uintptr_t>(virt) >> 39) & 0x1FF;
//Find the entries
pml4t_t pml4t = reinterpret_cast<pml4t_t>(0x70000);
//Init new page if necessary
if(!(reinterpret_cast<uintptr_t>(pml4t[pml4]) & PRESENT)){
pml4t[pml4] = reinterpret_cast<pdpt_t>(init_new_page() | (PRESENT | WRITEABLE));
}
auto pdpt = reinterpret_cast<pdpt_t>(reinterpret_cast<uintptr_t>(pml4t[pml4]) & ~0xFFF);
//Init new page if necessary
if(!(reinterpret_cast<uintptr_t>(pdpt[directory_ptr]) & PRESENT)){
pdpt[directory_ptr] = reinterpret_cast<pdt_t>(init_new_page() | (PRESENT | WRITEABLE));
}
auto pdt = reinterpret_cast<pdt_t>(reinterpret_cast<uintptr_t>(pdpt[directory_ptr]) & ~0xFFF);
//Init new page if necessary
if(!(reinterpret_cast<uintptr_t>(pdt[directory]) & PRESENT)){
pdt[directory] = reinterpret_cast<pt_t>(init_new_page() | (PRESENT | WRITEABLE));
}
auto pt = reinterpret_cast<pt_t>(reinterpret_cast<uintptr_t>(pdt[directory]) & ~0xFFF);
//Identity map the physical address
pt[table] = reinterpret_cast<page_entry>(reinterpret_cast<uintptr_t>(physical) | 0x3);
//Check if the page is already present
if(reinterpret_cast<uintptr_t>(pt[table]) & PRESENT){
//If the page is already set to the correct value, return true
//If the page is set to another value, return false
return reinterpret_cast<uintptr_t>(pt[table]) == (reinterpret_cast<uintptr_t>(virt) | (PRESENT | WRITEABLE));
}
//TODO Check if pt[table] is already used and if so, return false
//Identity map the physical address
pt[table] = reinterpret_cast<page_entry>(reinterpret_cast<uintptr_t>(virt) | (PRESENT | WRITEABLE));
return true;
}
bool paging::identity_map(void* physical, size_t pages){
bool paging::identity_map(void* virt, size_t pages){
//The address must be page-aligned
if(reinterpret_cast<uintptr_t>(physical) % PAGE_SIZE != 0){
if(!page_aligned(virt)){
return false;
}
//TODO This should first check each page for the present bit
//To avoid mapping only a subset of the pages
//check if one of the page is already mapped to another value
for(size_t page = 0; page < pages; ++page){
if(!identity_map(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(physical) + page * PAGE_SIZE))){
auto addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(virt) + page * PAGE_SIZE);
if(!page_free_or_set(addr, addr)){
return false;
}
}
//Identity map each page
for(size_t page = 0; page < pages; ++page){
if(!identity_map(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(virt) + page * PAGE_SIZE))){
return false;
}
}

View File

@ -516,9 +516,11 @@ void cat_command(const vector<string>& params){
}
void shutdown_command(const vector<string>&){
k_print_line("Init ACPI");
if(!acpi::init()){
k_print_line("Unable to init ACPI");
}
acpi::init();
acpi::shutdown();
}
} //end of anonymous namespace

View File

@ -36,7 +36,7 @@ void decode_bytes (int data, int descriptor[16], int *next){
}
void get_cache_info() {
int next = 0, i = 0;
/*int next = 0, i = 0;
int descriptor[256];
int mem_count;
@ -199,7 +199,7 @@ void get_cache_info() {
k_print_line(" 64-byte prefetching");
if ( descriptor[i] == 0xF1)
k_print_line(" 128-byte prefetching");
}
}*/
}
// EDX Features

View File

@ -8,6 +8,16 @@
#include "utils.hpp"
#include "string.hpp"
void memset(void* ptr, unsigned char value, size_t num){
auto p = static_cast<unsigned char*>(ptr);
--p;
while(num--){
*++p = value;
}
}
bool str_equals(const char* a, const char* b){
while(*a && *a == *b){
++a;