Files

96 lines
3.3 KiB
C

#include "rng.h"
#include "cpuid.h"
#include "cmos.h"
// GNU Assembler in devel VM is too old to recognize RDRAND & RDSEED instruction,
// so this is the machine code for two instructions:
// 0f c7 f0 RDRAND %eax
// c3 RET
char rng_rdrand_machine_code[] = {0x0f, 0xc7, 0xf0, 0xc3};
// and this is the machine code for two instructions:
// 0f c7 f8 RDSEED %eax
// c3 RET
char rng_rdseed_machine_code[] = {0x0f, 0xc7, 0xf8, 0xc3};
// This machine code can be easily regenerated with an up to date GCC and/or GAS.
uint32_t rand_num = 0; // Previous generated random number
/* void rng_init()
* @output: RNG initialized with current time
* @description: seed the RNG with CMOS time
*/
void rng_init() {
if(cpu_info.features_ext2_ebx.rdseed) {
// GAS in devel VM is too old to recognize RDSEED instruction,
// so I put machine code in array rng_x86_instructions on top of this file.
// C won't let me directly call an array, so I use an assembly call.
asm volatile("call rng_rdseed_machine_code" : "=a"(rand_num) : : "memory");
if(rand_num) return;
}
datetime_t time = cmos_datetime();
rand_num = time.second
+ time.minute * RNG_SEC_IN_MIN
+ time.hour * RNG_SEC_IN_HOUR
+ time.day * RNG_SEC_IN_DAY
+ time.month * RNG_SEC_IN_MONTH
+ time.year * RNG_SEC_IN_YEAR;
}
/* uint32_t rng_generate()
* @output: next random number in sequence
* @description: generates a random number with LCG algorithm
* described at https://en.wikipedia.org/wiki/Linear_congruential_generator
* Calls should be CLI/STIed, or multiple processes may get the same number.
* Optionally, if CPU supports it, uses x86 RDRAND instruction to generate a
* more random number. (However unsupported by GAS)
*/
uint32_t rng_generate() {
uint32_t d = 0;
if(cpu_info.features_ext.rdrnd) {
// GAS in devel VM is too old to recognize RDRAND instruction,
// so I put machine code in array rng_x86_instructions on top of this file.
// C won't let me directly call an array, so I use an assembly call.
asm volatile("call rng_rdrand_machine_code" : "=a"(d) : : "memory");
if(d) return d;
}
return rand_num = RNG_MASK & (RNG_MULTIPLIER * rand_num + RNG_INCREMENT);
}
// Unified FS interface for RTC.
unified_fs_interface_t rng_if = {
.open = rng_open,
.read = rng_read,
.write = NULL,
.ioctl = NULL,
.close = rng_close
};
/* int32_t rng_open(int32_t* inode, char* filename)
* @input: all ignored
* @output: 0 (SUCCESS)
* @description: open a RNG handle.
*/
int32_t rng_open(int32_t* inode, char* filename) {
return 0;
}
/* int32_t rng_read(int32_t* inode, uint32_t* offset, char* buf, uint32_t len)
* @input: buf, len - ptr and size of buffer
* @output: 0 (SUCCESS)
* @description: write a random number into the buffer.
*/
int32_t rng_read(int32_t* inode, uint32_t* offset, char* buf, uint32_t len) {
if(len < sizeof(uint32_t)) return FAIL;
*(uint32_t*) buf = rng_generate();
return sizeof(uint32_t);
}
/* int32_t rng_close(int32_t* inode)
* @input: inode - ignored
* @output: 0 (SUCCESS)
* @description: close RNG, currently does nothing
*/
int32_t rng_close(int32_t* inode) {
return 0;
}