1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use core::ptr;
use uefi::guid::GLOBAL_VARIABLE_GUID;
use uefi::status::{Error, Result};

use crate::ffi::wstr;
use crate::system_table;

fn get(name: &str, data: &mut [u8]) -> Result<usize> {
    let wname = wstr(name);
    let mut data_size = data.len();
    (system_table().RuntimeServices.GetVariable)(wname.as_ptr(), &GLOBAL_VARIABLE_GUID, ptr::null_mut(), &mut data_size, data.as_mut_ptr())?;
    Ok(data_size)
}

fn set(name: &str, data: &[u8]) -> Result<usize> {
    let wname = wstr(name);
    let access = 1 | 2 | 4;
    let data_size = data.len();
    (system_table().RuntimeServices.SetVariable)(wname.as_ptr(), &GLOBAL_VARIABLE_GUID, access, data_size, data.as_ptr())?;
    Ok(data_size)
}

pub fn get_boot_current() -> Result<u16> {
    let mut data = [0; 2];
    let count = get("BootCurrent", &mut data)?;
    if count == 2 {
        Ok((data[0] as u16) | ((data[1] as u16) << 8))
    } else {
        Err(Error::LoadError)
    }
}

pub fn get_boot_next() -> Result<u16> {
    let mut data = [0; 2];
    let count = get("BootNext", &mut data)?;
    if count == 2 {
        Ok((data[0] as u16) | ((data[1] as u16) << 8))
    } else {
        Err(Error::LoadError)
    }
}

pub fn set_boot_next(num_opt: Option<u16>) -> Result<usize> {
    if let Some(num) = num_opt {
        set("BootNext", &[
            num as u8,
            (num >> 8) as u8
        ])
    } else {
        set("BootNext", &[])
    }
}

pub fn get_boot_order() -> Result<Vec<u16>> {
    let mut data = [0; 4096];
    let count = get("BootOrder", &mut data)?;

    let mut order = vec![];
    for chunk in data[..count].chunks(2) {
        if chunk.len() == 2 {
            order.push((chunk[0] as u16) | (chunk[1] as u16) << 8);
        }
    }
    Ok(order)
}

pub fn get_boot_item(num: u16) -> Result<Vec<u8>> {
    let mut data = [0; 4096];
    let count = get(&format!("Boot{:>04X}", num), &mut data)?;
    if count < 6 {
        Err(Error::LoadError)
    } else {
        Ok(data[..count].to_vec())
    }
}

pub fn set_boot_item(num: u16, data: &[u8]) -> Result<usize> {
    set(&format!("Boot{:>04X}", num), &data)
}

pub fn get_os_indications() -> Result<u64> {
    let mut data = [0; 8];
    let count = get("OsIndications", &mut data)?;
    if count == 8 {
        Ok(
            (data[0] as u64) |
            ((data[1] as u64) << 8) |
            ((data[2] as u64) << 16) |
            ((data[3] as u64) << 24) |
            ((data[4] as u64) << 32) |
            ((data[5] as u64) << 40) |
            ((data[6] as u64) << 48) |
            ((data[7] as u64) << 56)
        )
    } else {
        Err(Error::LoadError)
    }
}

pub fn set_os_indications(indications_opt: Option<u64>) -> Result<usize> {
    if let Some(indications) = indications_opt {
        set("OsIndications", &[
            indications as u8,
            (indications >> 8) as u8,
            (indications >> 16) as u8,
            (indications >> 24) as u8,
            (indications >> 32) as u8,
            (indications >> 40) as u8,
            (indications >> 48) as u8,
            (indications >> 56) as u8
        ])
    } else {
        set("OsIndications", &[])
    }
}

pub fn get_os_indications_supported() -> Result<u64> {
    let mut data = [0; 8];
    let count = get("OsIndicationsSupported", &mut data)?;
    if count == 8 {
        Ok(
            (data[0] as u64) |
            ((data[1] as u64) << 8) |
            ((data[2] as u64) << 16) |
            ((data[3] as u64) << 24) |
            ((data[4] as u64) << 32) |
            ((data[5] as u64) << 40) |
            ((data[6] as u64) << 48) |
            ((data[7] as u64) << 56)
        )
    } else {
        Err(Error::LoadError)
    }
}