Espresso 0.0.2a
This commit is contained in:
124
lib/ksymtab.c
124
lib/ksymtab.c
@ -1,124 +0,0 @@
|
||||
|
||||
|
||||
#include <ksymtab.h>
|
||||
|
||||
|
||||
|
||||
|
||||
#define KFUNC_TABLE_ADDRESS 0xC0101000
|
||||
|
||||
#define KSYMTAB_MAX 0x8086FF
|
||||
|
||||
#define IS_MODULE_FUNC(id) ((id) & 0x80000000)
|
||||
#define GET_MODULE_ID(id) (((id) >> 20) & 0x7FF)
|
||||
#define GET_FUNC_ID(id) ((id) & 0xFFFFF)
|
||||
#define EXISTS(id) ((id) > 0x0)
|
||||
|
||||
#define MAKE_KERNEL_FUNC(id) ((id) & 0x7FFFFFFF)
|
||||
|
||||
#define MAKE_MODULE_FUNC(mid, fid) (0x80000000 | ((mid) << 20) | ((fid) & 0xFFFFF))
|
||||
|
||||
kfunc_t* kfunc_table = (kfunc_t*)KFUNC_TABLE_ADDRESS;
|
||||
|
||||
static uint32_t ktab_size = 0;
|
||||
|
||||
|
||||
uint64_t kfunc_call(kfunc_t* func, uint32_t a, uint32_t b, uint32_t c, uint32_t d)
|
||||
{
|
||||
uint32_t eax_ret, edx_ret;
|
||||
|
||||
asm volatile (
|
||||
"push %[d]\n\t"
|
||||
"push %[c]\n\t"
|
||||
"push %[b]\n\t"
|
||||
"push %[a]\n\t"
|
||||
"call *%[fn]\n\t"
|
||||
"add $16, %%esp\n\t" /* clean up stack (4 args * 4 bytes) */
|
||||
: "=a"(eax_ret), "=d"(edx_ret)
|
||||
: [a]"r"(a), [b]"r"(b), [c]"r"(c), [d]"r"(d), [fn]"r"(func->addr)
|
||||
: "memory"
|
||||
);
|
||||
|
||||
return ((uint64_t)edx_ret << 32) | eax_ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint64_t call_kfunc_by_id(uint32_t id, uint32_t a, uint32_t b, uint32_t c, uint32_t d)
|
||||
{
|
||||
for (int i = 0; i < (int)ktab_size; i++)
|
||||
{
|
||||
if (kfunc_table[i].id == id)
|
||||
{
|
||||
if (kfunc_table[i].addr == 0x0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return kfunc_call(&kfunc_table[i], a, b, c, d);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
uint32_t add_kfunc(void* addr, bool module, uint16_t module_id, uint32_t function_id)
|
||||
{
|
||||
if (ktab_size >= KSYMTAB_MAX)
|
||||
{
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
kfunc_t kf = make_kfunc(addr, module, module_id, function_id);
|
||||
kfunc_table[ktab_size] = kf;
|
||||
|
||||
ktab_size++;
|
||||
|
||||
return kf.id;
|
||||
}
|
||||
|
||||
/*
|
||||
Constructs and returns a kfunc_t:
|
||||
- 'addr' is the address of the function (can be NULL/0)
|
||||
- 'module' indicates if it's a module/driver function
|
||||
- 'module_id' is used only if 'module' is true (11 bits max)
|
||||
- 'function_id':
|
||||
- 20 bits if module is true
|
||||
- 31 bits if kernel function
|
||||
*/
|
||||
kfunc_t make_kfunc(void* addr, bool module, uint16_t module_id, uint32_t function_id)
|
||||
{
|
||||
uint32_t id;
|
||||
|
||||
if (module)
|
||||
{
|
||||
id = 0x80000000 | ((module_id & 0x7FF) << 20) | (function_id & 0xFFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (function_id == UINT32_MAX)
|
||||
{
|
||||
function_id = ktab_size;
|
||||
}
|
||||
id = function_id & 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
kfunc_t result = {
|
||||
.id = id,
|
||||
.addr = (uint32_t)(uintptr_t)addr
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
kfunc_t* find_kfunc(uint32_t id)
|
||||
{
|
||||
for (uint32_t i = 0; i < ktab_size; i++)
|
||||
{
|
||||
if (kfunc_table[i].id == id)
|
||||
{
|
||||
return &kfunc_table[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
37
lib/math.c
Normal file
37
lib/math.c
Normal file
@ -0,0 +1,37 @@
|
||||
#include <types.h>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
|
||||
static int ps_of_two[12] = { 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096 };
|
||||
|
||||
bool is_low_power_of_two(int n)
|
||||
{
|
||||
for (int i = 0; i < 11; i++)
|
||||
{
|
||||
if (n == ps_of_two[i])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t int_pow(uint64_t base, uint32_t exp)
|
||||
{
|
||||
uint64_t result = 1;
|
||||
|
||||
while (exp)
|
||||
{
|
||||
if (exp & 1)
|
||||
{
|
||||
result *= base;
|
||||
}
|
||||
|
||||
exp >>= 1;
|
||||
base *= base;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
190
lib/mm/heap.c
190
lib/mm/heap.c
@ -1,76 +1,138 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <mm/heap.h>
|
||||
#include <mm/pmm.h>
|
||||
#include <mm/paging.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <mm_macros.h>
|
||||
|
||||
#include <mm/heap.h>
|
||||
|
||||
#define ALIGNMENT 8
|
||||
#define ALIGN(size) (((size) + (ALIGNMENT - 1)) & ~(ALIGNMENT - 1))
|
||||
#define ALIGN4(x) (((x) + 3) & ~3)
|
||||
#define MIN_BLOCK_SIZE 16
|
||||
|
||||
typedef struct block_header {
|
||||
typedef struct block {
|
||||
size_t size;
|
||||
struct block_header* next;
|
||||
struct block* next;
|
||||
int free;
|
||||
} block_header_t;
|
||||
} block_t;
|
||||
|
||||
#define BLOCK_SIZE sizeof(block_header_t)
|
||||
#define BLOCK_SIZE sizeof(block_t)
|
||||
|
||||
static uint8_t* heap_base = (uint8_t*)HEAP_START;
|
||||
static uint8_t* heap_end = (uint8_t*)(HEAP_START + HEAP_SIZE);
|
||||
static uint8_t* heap_base;
|
||||
static uint8_t* heap_end;
|
||||
static size_t heap_size;
|
||||
static block_t* free_list;
|
||||
|
||||
static block_header_t* free_list = NULL;
|
||||
|
||||
|
||||
void heap_init(void)
|
||||
void heap_init(uint32_t start, uint32_t size)
|
||||
{
|
||||
free_list = (block_header_t*)heap_base;
|
||||
free_list->size = HEAP_SIZE - BLOCK_SIZE;
|
||||
free_list->next = NULL;
|
||||
#ifdef _DEBUG
|
||||
printf("[ HEAP ] Initializing heap allocator...\n");
|
||||
#endif
|
||||
|
||||
heap_base = (uint8_t*) ALIGN4((uintptr_t) start);
|
||||
heap_end = heap_base;
|
||||
heap_size = size;
|
||||
free_list = NULL;
|
||||
|
||||
for (uint32_t i = 0; i < size; i += 0x1000)
|
||||
{
|
||||
map_page(pmm_alloc_page(), (void*)(start + i));
|
||||
}
|
||||
|
||||
/* Set up initial free block */
|
||||
free_list = (block_t*)heap_base;
|
||||
free_list->size = heap_size - BLOCK_SIZE;
|
||||
free_list->free = 1;
|
||||
free_list->next = NULL;
|
||||
|
||||
heap_end = heap_base + size;
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("[ HEAP ] Heap allocator initialized\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void* malloc(size_t size)
|
||||
static block_t* find_free_block(size_t size)
|
||||
{
|
||||
size = ALIGN(size);
|
||||
block_header_t* curr = free_list;
|
||||
|
||||
block_t* curr = free_list;
|
||||
while (curr)
|
||||
{
|
||||
if (curr->free && curr->size >= size)
|
||||
{
|
||||
/* Split if there's space for another block */
|
||||
if (curr->size >= size + BLOCK_SIZE + ALIGNMENT)
|
||||
{
|
||||
block_header_t* new_block = (block_header_t*)((uint8_t*)curr + BLOCK_SIZE + size);
|
||||
new_block->size = curr->size - size - BLOCK_SIZE;
|
||||
new_block->next = curr->next;
|
||||
new_block->free = 1;
|
||||
|
||||
curr->next = new_block;
|
||||
curr->size = size;
|
||||
}
|
||||
|
||||
curr->free = 0;
|
||||
return (void*)((uint8_t*)curr + BLOCK_SIZE);
|
||||
return curr;
|
||||
}
|
||||
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
printd("Malloc failed due to lack of free memory\n");
|
||||
|
||||
printf("find_free_block(): No free block found!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void split_block(block_t* blk, size_t size)
|
||||
{
|
||||
if (blk->size >= size + BLOCK_SIZE + MIN_BLOCK_SIZE)
|
||||
{
|
||||
block_t* new_blk = (block_t*)((uint8_t*)blk + BLOCK_SIZE + size);
|
||||
new_blk->size = blk->size - size - BLOCK_SIZE;
|
||||
new_blk->free = 1;
|
||||
new_blk->next = blk->next;
|
||||
blk->next = new_blk;
|
||||
blk->size = size;
|
||||
}
|
||||
}
|
||||
|
||||
void* malloc(size_t size)
|
||||
{
|
||||
size = ALIGN4(size);
|
||||
block_t* blk = find_free_block(size);
|
||||
|
||||
if (!blk)
|
||||
{
|
||||
printf("malloc(): No free block found!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
split_block(blk, size);
|
||||
blk->free = 0;
|
||||
return (void*)((uint8_t*)blk + BLOCK_SIZE);
|
||||
}
|
||||
|
||||
void free(void* ptr)
|
||||
{
|
||||
if (!ptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
block_t* blk = (block_t*)((uint8_t*)ptr - BLOCK_SIZE);
|
||||
blk->free = 1;
|
||||
|
||||
/* coalesce */
|
||||
block_t* curr = free_list;
|
||||
while (curr && curr->next)
|
||||
{
|
||||
if (curr->free && curr->next->free)
|
||||
{
|
||||
curr->size += BLOCK_SIZE + curr->next->size;
|
||||
curr->next = curr->next->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
curr = curr->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void* calloc(size_t nmemb, size_t size)
|
||||
{
|
||||
size_t total = nmemb * size;
|
||||
void* ptr = malloc(total);
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
memset(ptr, 0, total);
|
||||
MEMSET(ptr, 0, total);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@ -81,57 +143,25 @@ void* realloc(void* ptr, size_t size)
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
if (size == 0)
|
||||
if (!size)
|
||||
{
|
||||
free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
block_header_t* block = (block_header_t*)((uint8_t*)ptr - BLOCK_SIZE);
|
||||
if (block->size >= size)
|
||||
block_t* blk = (block_t*)((uint8_t*)ptr - BLOCK_SIZE);
|
||||
if (blk->size >= size)
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* new_ptr = malloc(size);
|
||||
if (new_ptr) {
|
||||
memcpy(new_ptr, ptr, block->size);
|
||||
|
||||
if (new_ptr)
|
||||
{
|
||||
memcpy(new_ptr, ptr, blk->size);
|
||||
free(ptr);
|
||||
}
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
void free(void* ptr)
|
||||
{
|
||||
if (!ptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
block_header_t* block = (block_header_t*)((uint8_t*)ptr - BLOCK_SIZE);
|
||||
block->free = 1;
|
||||
|
||||
/* Forward coalescing */
|
||||
if (block->next && block->next->free)
|
||||
{
|
||||
block->size += BLOCK_SIZE + block->next->size;
|
||||
block->next = block->next->next;
|
||||
}
|
||||
|
||||
/* Backward coalescing */
|
||||
block_header_t* prev = NULL;
|
||||
block_header_t* curr = free_list;
|
||||
|
||||
while (curr && curr != block)
|
||||
{
|
||||
prev = curr;
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
if (prev && prev->free)
|
||||
{
|
||||
prev->size += BLOCK_SIZE + block->size;
|
||||
prev->next = block->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
110
lib/mm/paging.c
110
lib/mm/paging.c
@ -1,82 +1,60 @@
|
||||
#include <mm/pmm.h>
|
||||
#include <string.h>
|
||||
#include <mm_macros.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <mm/paging.h>
|
||||
#include <mm/pmm.h>
|
||||
#include <mm/heap.h>
|
||||
|
||||
#define PAGE_DIRECTORY_ENTRIES 1024
|
||||
#define PAGE_TABLE_ENTRIES 1024
|
||||
#define PAGE_SIZE 4096
|
||||
#define PAGE_PRESENT 0x1
|
||||
#define PAGE_WRITE 0x2
|
||||
#define PAGE_SIZE 4096
|
||||
|
||||
typedef uint32_t page_directory_entry_t;
|
||||
typedef uint32_t page_table_entry_t;
|
||||
|
||||
static page_directory_entry_t* page_directory = NULL; /* Will be allocated */
|
||||
static page_table_entry_t* page_tables[PAGE_DIRECTORY_ENTRIES];
|
||||
|
||||
extern void _enable_paging_asm(void);
|
||||
|
||||
void paging_init(void)
|
||||
{
|
||||
/* Allocate and clear the page directory */
|
||||
page_directory = (page_directory_entry_t*)alloc_page();
|
||||
memset(page_directory, 0, PAGE_SIZE);
|
||||
|
||||
/* Allocate and set up the first identity-mapped page table (0-4MB) */
|
||||
page_tables[0] = (page_table_entry_t*)alloc_page();
|
||||
memset(page_tables[0], 0, PAGE_SIZE);
|
||||
for (uint32_t i = 0; i < PAGE_TABLE_ENTRIES; i++)
|
||||
{
|
||||
page_tables[0][i] = (i * PAGE_SIZE) | 3; /* Present | RW */
|
||||
}
|
||||
page_directory[0] = ((uint32_t)page_tables[0]) | 3;
|
||||
|
||||
/* Allocate and clear the heap page table */
|
||||
uint32_t heap_pd_index = HEAP_START >> 22; /* 0xC0000000 >> 22 = 768 */
|
||||
page_tables[heap_pd_index] = (page_table_entry_t*)alloc_page();
|
||||
memset(page_tables[heap_pd_index], 0, PAGE_SIZE);
|
||||
|
||||
/* Map 4MB heap pages */
|
||||
for (uint32_t i = 0; i < PAGE_TABLE_ENTRIES; i++) /* 1024 pages = 4MB */
|
||||
{
|
||||
void* phys = alloc_page();
|
||||
if (phys == 0)
|
||||
{
|
||||
printf("Out of physical memory during heap mapping!\n");
|
||||
while (1);
|
||||
}
|
||||
page_tables[heap_pd_index][i] = ((uint32_t)phys & 0xFFFFF000) | 3; /* Present | RW */
|
||||
}
|
||||
page_directory[heap_pd_index] = ((uint32_t)page_tables[heap_pd_index]) | 3;
|
||||
|
||||
/* Load page directory */
|
||||
asm volatile ("mov %0, %%cr3" : : "r"(page_directory));
|
||||
|
||||
/* Enable paging */
|
||||
_enable_paging_asm();
|
||||
}
|
||||
static uint32_t* page_directory;
|
||||
|
||||
void map_page(void* phys_addr, void* virt_addr)
|
||||
{
|
||||
uint32_t pd_index = ((uint32_t)virt_addr >> 22) & 0x3FF;
|
||||
uint32_t pt_index = ((uint32_t)virt_addr >> 12) & 0x3FF;
|
||||
uint32_t pd_idx = ((uint32_t)virt_addr >> 22) & 0x3FF;
|
||||
uint32_t pt_idx = ((uint32_t)virt_addr >> 12) & 0x3FF;
|
||||
|
||||
/* Allocate page table if necessary */
|
||||
if (!(page_directory[pd_index] & 1))
|
||||
uint32_t* page_table;
|
||||
|
||||
if (!(page_directory[pd_idx] & PAGE_PRESENT))
|
||||
{
|
||||
void* pt_phys = alloc_page();
|
||||
page_tables[pd_index] = (page_table_entry_t*)((uint32_t)pt_phys + 0xC0000000); /* Map it higher */
|
||||
|
||||
memset(page_tables[pd_index], 0, PAGE_SIZE);
|
||||
|
||||
page_directory[pd_index] = ((uint32_t)pt_phys) | 0x3; /* Present, R/W */
|
||||
page_table = (uint32_t*) pmm_alloc_page();
|
||||
MEMSET(page_table, 0, PAGE_SIZE);
|
||||
page_directory[pd_idx] = ((uint32_t)page_table) | PAGE_PRESENT | PAGE_WRITE;
|
||||
}
|
||||
else
|
||||
{
|
||||
page_table = (uint32_t*)(page_directory[pd_idx] & ~0xFFF);
|
||||
}
|
||||
|
||||
page_table_entry_t* page_table = (page_table_entry_t*)((page_directory[pd_index] & 0xFFFFF000) + 0xC0000000);
|
||||
page_table[pt_index] = ((uint32_t)phys_addr & 0xFFFFF000) | 0x3; /* Present, R/W */
|
||||
|
||||
asm volatile ("invlpg (%0)" :: "r" (virt_addr) : "memory");
|
||||
page_table[pt_idx] = ((uint32_t)phys_addr) | PAGE_PRESENT | PAGE_WRITE;
|
||||
}
|
||||
|
||||
void paging_init(void)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
printf("[ PAGING ] Initializing paging...\n");
|
||||
#endif
|
||||
|
||||
page_directory = (uint32_t*)pmm_alloc_page();
|
||||
|
||||
MEMSET(page_directory, 0, PAGE_SIZE);
|
||||
|
||||
for (uint32_t addr = 0; addr < 0x800000; addr += PAGE_SIZE)
|
||||
{
|
||||
map_page((void*) addr, (void*) addr); /* identity map first 8MB */
|
||||
}
|
||||
|
||||
asm volatile("mov %0, %%cr3" :: "r"(page_directory));
|
||||
uint32_t cr0;
|
||||
asm volatile("mov %%cr0, %0" : "=r"(cr0));
|
||||
cr0 |= 0x80000000;
|
||||
asm volatile("mov %0, %%cr0" :: "r"(cr0));
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("[ PAGING ] Paging initialized\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
98
lib/mm/pmm.c
98
lib/mm/pmm.c
@ -1,80 +1,76 @@
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <mm/pmm.h>
|
||||
|
||||
#define PAGE_SIZE 4096
|
||||
#define BITMAP_SIZE (1024 * 1024) /* Supports up to 4GB RAM (1 bit per page) */
|
||||
|
||||
static uint8_t bitmap[BITMAP_SIZE / 8];
|
||||
static uint32_t total_pages;
|
||||
static uint32_t used_pages = 0;
|
||||
#define MAX_PAGES (1024 * 1024) /* 4GB / 4KB */
|
||||
static uint8_t bitmap[MAX_PAGES / 8] __attribute__((section(".pmm_bitmap")));
|
||||
static size_t total_pages;
|
||||
|
||||
static inline void set_bit(uint32_t idx)
|
||||
#define BITMAP_SET(i) (bitmap[(i) / 8] |= (1 << ((i) % 8)))
|
||||
#define BITMAP_CLEAR(i) (bitmap[(i) / 8] &= ~(1 << ((i) % 8)))
|
||||
#define BITMAP_TEST(i) (bitmap[(i) / 8] & (1 << ((i) % 8)))
|
||||
|
||||
void pmm_init(multiboot_info_t* mb)
|
||||
{
|
||||
bitmap[idx / 8] |= (1 << (idx % 8));
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
printf("[ PMM ] Initializing physical memory manager...\n");
|
||||
#endif
|
||||
|
||||
static inline void clear_bit(uint32_t idx)
|
||||
{
|
||||
bitmap[idx / 8] &= ~(1 << (idx % 8));
|
||||
}
|
||||
|
||||
static inline int test_bit(uint32_t idx)
|
||||
{
|
||||
return (bitmap[idx / 8] >> (idx % 8)) & 1;
|
||||
}
|
||||
|
||||
void pmm_init(multiboot_info_t* mb_info)
|
||||
{
|
||||
total_pages = 0x100000; /* 4GB / 4KB = 1M pages */
|
||||
for (uint32_t i = 0; i < total_pages / 8; i++)
|
||||
total_pages = MAX_PAGES;
|
||||
|
||||
for (uint32_t i = 0; i < (total_pages / 8); i++)
|
||||
{
|
||||
bitmap[i] = 0xFF; /* Mark all as used */
|
||||
bitmap[i] = 0xFF;
|
||||
}
|
||||
|
||||
multiboot_memory_map_t* mmap = (multiboot_memory_map_t*) mb_info->mmap_addr;
|
||||
while ((uint32_t)mmap < mb_info->mmap_addr + mb_info->mmap_length)
|
||||
multiboot_memory_map_t* mmap = (void*)(uintptr_t)mb->mmap_addr;
|
||||
size_t entries = mb->mmap_length / sizeof(multiboot_memory_map_t);
|
||||
|
||||
for (size_t i = 0; i < entries; i++)
|
||||
{
|
||||
if (mmap->type == 1) /* Usable */
|
||||
if (mmap[i].type == 1) /* usable */
|
||||
{
|
||||
uint64_t base = mmap->addr;
|
||||
uint64_t len = mmap->len;
|
||||
for (uint64_t addr = base; addr < base + len; addr += PAGE_SIZE)
|
||||
uint64_t start = mmap[i].addr;
|
||||
uint64_t end = start + mmap[i].len;
|
||||
for (uint64_t addr = start; addr < end; addr += 0x1000)
|
||||
{
|
||||
if (addr >= 0x210000) /* Skip first 2.1MB, or ≈ 2.06MiB */
|
||||
if (addr >= 0x100000) /* skip below 1MB */
|
||||
{
|
||||
uint32_t idx = addr / PAGE_SIZE;
|
||||
|
||||
if (idx >= total_pages)
|
||||
{
|
||||
continue; /* skip entries above 4GB */
|
||||
}
|
||||
|
||||
clear_bit(idx);
|
||||
used_pages--;
|
||||
size_t idx = addr / 0x1000;
|
||||
BITMAP_CLEAR(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
mmap = (multiboot_memory_map_t*)((uint32_t)mmap + mmap->size + sizeof(mmap->size));
|
||||
}
|
||||
total_pages = MAX_PAGES;
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("[ PMM ] Physical memory manager initialized\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void* alloc_page(void) {
|
||||
for (uint32_t i = 0; i < total_pages; i++)
|
||||
void* pmm_alloc_page(void)
|
||||
{
|
||||
for (uint32_t i = 0; i < total_pages; ++i)
|
||||
{
|
||||
if (!test_bit(i))
|
||||
if (!BITMAP_TEST(i))
|
||||
{
|
||||
set_bit(i);
|
||||
used_pages++;
|
||||
return (void*)(i * PAGE_SIZE);
|
||||
BITMAP_SET(i);
|
||||
return (void*)(i * 4096);
|
||||
}
|
||||
}
|
||||
return NULL; /* Out of memory */
|
||||
|
||||
printf("pmm_alloc_page(): No free page found!\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void free_page(void* ptr)
|
||||
|
||||
void pmm_free_page(void* addr)
|
||||
{
|
||||
uint32_t idx = (uint32_t)ptr / PAGE_SIZE;
|
||||
clear_bit(idx);
|
||||
size_t idx = (uintptr_t)addr / 0x1000;
|
||||
BITMAP_CLEAR(idx);
|
||||
}
|
||||
|
||||
|
||||
505
lib/printf.c
505
lib/printf.c
@ -2,219 +2,422 @@
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <drivers/serio.h>
|
||||
|
||||
#include <printf.h>
|
||||
|
||||
static uint8_t color = 0xFF;
|
||||
|
||||
void printwc(const char* str, uint8_t color)
|
||||
{
|
||||
uint8_t c = terminal_getcolor();
|
||||
|
||||
terminal_setcolor(color);
|
||||
|
||||
printf(str);
|
||||
|
||||
terminal_setcolor(c);
|
||||
}
|
||||
|
||||
void printd(const char* str)
|
||||
{
|
||||
terminal_debug_writestring(str);
|
||||
|
||||
serial_puts("[ DEBUG ] ");
|
||||
serial_puts(str);
|
||||
}
|
||||
|
||||
void printdc(const char* str, uint8_t color)
|
||||
{
|
||||
uint8_t c = terminal_getcolor();
|
||||
terminal_setcolor(color);
|
||||
|
||||
printd(str);
|
||||
|
||||
terminal_setcolor(c);
|
||||
}
|
||||
|
||||
void printf_set_color(uint8_t _color)
|
||||
{
|
||||
if (_color == 0xFF)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
color = _color;
|
||||
}
|
||||
|
||||
void printf(const char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
if (color != 0xFF)
|
||||
{
|
||||
terminal_setcolor(color);
|
||||
}
|
||||
|
||||
for (size_t i = 0; format[i] != '\0'; ++i) {
|
||||
if (format[i] == '%' && format[i + 1] != '\0') {
|
||||
++i;
|
||||
for (size_t i = 0; format[i] != '\0'; ++i)
|
||||
{
|
||||
if (format[i] == '%' && format[i + 1] != '\0')
|
||||
{
|
||||
++i;
|
||||
|
||||
// Check for width (like %016llx)
|
||||
int width = 0;
|
||||
if (format[i] == '0') {
|
||||
++i;
|
||||
while (format[i] >= '0' && format[i] <= '9') {
|
||||
width = width * 10 + (format[i] - '0');
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for 'll' prefix
|
||||
bool is_ll = false;
|
||||
if (format[i] == 'l' && format[i + 1] == 'l') {
|
||||
is_ll = true;
|
||||
i += 2;
|
||||
}
|
||||
|
||||
switch (format[i]) {
|
||||
case 's': {
|
||||
const char* str = va_arg(args, const char*);
|
||||
terminal_writestring(str ? str : "(null)");
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
char c = (char) va_arg(args, int);
|
||||
terminal_putchar(c);
|
||||
break;
|
||||
}
|
||||
case 'd':
|
||||
case 'i': {
|
||||
int32_t val = va_arg(args, int32_t);
|
||||
print_int(val);
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
uint32_t val = va_arg(args, uint32_t);
|
||||
print_uint(val);
|
||||
break;
|
||||
}
|
||||
case 'x': {
|
||||
if (is_ll) {
|
||||
uint64_t val = va_arg(args, uint64_t);
|
||||
print_hex64(val, width ? width : 16, false);
|
||||
} else {
|
||||
uint32_t val = va_arg(args, uint32_t);
|
||||
print_hex(val, width ? width : 8, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'X': {
|
||||
if (is_ll) {
|
||||
uint64_t val = va_arg(args, uint64_t);
|
||||
print_hex64(val, width ? width : 16, true);
|
||||
} else {
|
||||
uint32_t val = va_arg(args, uint32_t);
|
||||
print_hex(val, width ? width : 8, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'p': {
|
||||
void* ptr = va_arg(args, void*);
|
||||
terminal_writestring("0x");
|
||||
print_hex((uint32_t)(uintptr_t)ptr, 8, true); // assumes 32-bit pointer
|
||||
break;
|
||||
}
|
||||
case 'f':
|
||||
case 'F': {
|
||||
double val = va_arg(args, double);
|
||||
print_double(val, 2);
|
||||
break;
|
||||
}
|
||||
case '%': {
|
||||
terminal_putchar('%');
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
terminal_putchar('%');
|
||||
terminal_putchar(format[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
terminal_putchar(format[i]);
|
||||
int width = 0;
|
||||
if (format[i] == '0')
|
||||
{
|
||||
++i;
|
||||
while (format[i] >= '0' && format[i] <= '9')
|
||||
{
|
||||
width = width * 10 + (format[i] - '0');
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
bool is_ll = false;
|
||||
if (format[i] == 'l' && format[i + 1] == 'l')
|
||||
{
|
||||
is_ll = true;
|
||||
i += 2;
|
||||
}
|
||||
|
||||
switch (format[i])
|
||||
{
|
||||
case 's': {
|
||||
const char* str = va_arg(args, const char*);
|
||||
|
||||
terminal_writestring(str ? str : "(null)");
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_puts(str ? str : "(null)");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
char c = (char) va_arg(args, int);
|
||||
terminal_putchar(c);
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write(c);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 'd':
|
||||
case 'i': {
|
||||
if (is_ll)
|
||||
{
|
||||
int64_t val = va_arg(args, int64_t);
|
||||
print_lint(val);
|
||||
}
|
||||
else
|
||||
{
|
||||
int32_t val = va_arg(args, int32_t);
|
||||
print_int(val);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
if (is_ll)
|
||||
{
|
||||
uint64_t val = va_arg(args, uint64_t);
|
||||
print_luint(val);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t val = va_arg(args, uint32_t);
|
||||
print_uint(val);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 'x': {
|
||||
if (is_ll)
|
||||
{
|
||||
uint64_t val = va_arg(args, uint64_t);
|
||||
print_hex64(val, width ? width : 16, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t val = va_arg(args, uint32_t);
|
||||
print_hex(val, width ? width : 8, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'X': {
|
||||
if (is_ll)
|
||||
{
|
||||
uint64_t val = va_arg(args, uint64_t);
|
||||
print_hex64(val, width ? width : 16, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t val = va_arg(args, uint32_t);
|
||||
print_hex(val, width ? width : 8, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'p': {
|
||||
void* ptr = va_arg(args, void*);
|
||||
terminal_writestring("0x");
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write('0');
|
||||
serial_write('x');
|
||||
}
|
||||
|
||||
print_hex((uint32_t)(uintptr_t)ptr, 8, true);
|
||||
|
||||
break;
|
||||
}
|
||||
case 'f':
|
||||
case 'F': {
|
||||
double val = va_arg(args, double);
|
||||
print_double(val, 2);
|
||||
break;
|
||||
}
|
||||
case '%': {
|
||||
terminal_putchar('%');
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write('%');
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
terminal_putchar('%');
|
||||
terminal_putchar(format[i]);
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write('%');
|
||||
serial_write(format[i]);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
terminal_putchar(format[i]);
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write(format[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
void print_int(int32_t value) {
|
||||
char buffer[12]; // Enough for 32-bit signed int (-2147483648)
|
||||
int i = 0;
|
||||
uint32_t u;
|
||||
void print_int(int32_t value)
|
||||
{
|
||||
char buffer[12];
|
||||
int i = 0;
|
||||
uint32_t u;
|
||||
|
||||
if (value < 0) {
|
||||
terminal_putchar('-');
|
||||
u = (uint32_t)(-value);
|
||||
} else {
|
||||
u = (uint32_t)value;
|
||||
if (value < 0)
|
||||
{
|
||||
terminal_putchar('-');
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write('-');
|
||||
}
|
||||
|
||||
u = (uint32_t)(-value);
|
||||
}
|
||||
else
|
||||
{
|
||||
u = (uint32_t)value;
|
||||
}
|
||||
|
||||
// Convert to string in reverse
|
||||
do {
|
||||
buffer[i++] = '0' + (u % 10);
|
||||
u /= 10;
|
||||
} while (u > 0);
|
||||
do
|
||||
{
|
||||
buffer[i++] = '0' + (u % 10);
|
||||
u /= 10;
|
||||
} while (u > 0);
|
||||
|
||||
// Print in correct order
|
||||
while (i--) {
|
||||
terminal_putchar(buffer[i]);
|
||||
while (i--)
|
||||
{
|
||||
terminal_putchar(buffer[i]);
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write(buffer[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_lint(int64_t value)
|
||||
{
|
||||
char buffer[21];
|
||||
int i = 0;
|
||||
uint64_t u;
|
||||
|
||||
if (value < 0)
|
||||
{
|
||||
terminal_putchar('-');
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write('-');
|
||||
}
|
||||
|
||||
u = (uint64_t) (-value);
|
||||
}
|
||||
else
|
||||
{
|
||||
u = (uint64_t) value;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
buffer[i++] = '0' + (u % 10);
|
||||
u /= 10;
|
||||
} while (u > 0);
|
||||
|
||||
while (i--)
|
||||
{
|
||||
terminal_putchar(buffer[i]);
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write(buffer[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_hex(uint32_t value, int width, bool uppercase)
|
||||
{
|
||||
const char* hex_chars = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
|
||||
char buffer[9]; // 8 hex digits max for 32-bit
|
||||
int i = 0;
|
||||
const char* hex_chars = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
|
||||
char buffer[9]; // 8 hex digits max for 32-bit
|
||||
int i = 0;
|
||||
|
||||
do {
|
||||
buffer[i++] = hex_chars[value & 0xF];
|
||||
value >>= 4;
|
||||
} while (value || i < width); // ensure at least 'width' digits
|
||||
do
|
||||
{
|
||||
buffer[i++] = hex_chars[value & 0xF];
|
||||
value >>= 4;
|
||||
} while (value || i < width); // ensure at least 'width' digits
|
||||
|
||||
while (i--) {
|
||||
terminal_putchar(buffer[i]);
|
||||
while (i--)
|
||||
{
|
||||
terminal_putchar(buffer[i]);
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write(buffer[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_double(double value, int precision)
|
||||
{
|
||||
// Handle the integer part
|
||||
int32_t integer_part = (int32_t)value;
|
||||
double fractional_part = value - integer_part;
|
||||
// Handle the integer part
|
||||
int32_t integer_part = (int32_t)value;
|
||||
double fractional_part = value - integer_part;
|
||||
|
||||
// Print the integer part
|
||||
print_int(integer_part);
|
||||
// Print the integer part
|
||||
print_int(integer_part);
|
||||
|
||||
// Print the decimal point
|
||||
terminal_putchar('.');
|
||||
// Print the decimal point
|
||||
terminal_putchar('.');
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write('.');
|
||||
}
|
||||
|
||||
// Print the fractional part (scaled up)
|
||||
fractional_part *= 1;
|
||||
for (int i = 0; i < precision; i++) {
|
||||
fractional_part *= 10;
|
||||
// Print the fractional part (scaled up)
|
||||
fractional_part *= 1;
|
||||
for (int i = 0; i < precision; i++)
|
||||
{
|
||||
fractional_part *= 10;
|
||||
}
|
||||
|
||||
int32_t frac_int = (int32_t)fractional_part;
|
||||
print_int(frac_int);
|
||||
}
|
||||
|
||||
void print_uint(uint32_t value)
|
||||
{
|
||||
char buffer[11];
|
||||
int i = 0;
|
||||
|
||||
do
|
||||
{
|
||||
buffer[i++] = '0' + (value % 10);
|
||||
value /= 10;
|
||||
} while (value > 0);
|
||||
|
||||
while (i--)
|
||||
{
|
||||
terminal_putchar(buffer[i]);
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write(buffer[i]);
|
||||
}
|
||||
|
||||
int32_t frac_int = (int32_t)fractional_part;
|
||||
print_int(frac_int);
|
||||
}
|
||||
}
|
||||
|
||||
void print_uint(uint32_t value) {
|
||||
char buffer[11]; // Enough for 32-bit unsigned int
|
||||
int i = 0;
|
||||
void print_luint(uint64_t value)
|
||||
{
|
||||
char buffer[21];
|
||||
int i = 0;
|
||||
|
||||
do {
|
||||
buffer[i++] = '0' + (value % 10);
|
||||
value /= 10;
|
||||
} while (value > 0);
|
||||
do
|
||||
{
|
||||
buffer[i++] = '0' + (value % 10);
|
||||
value /= 10;
|
||||
} while (value > 0);
|
||||
|
||||
while (i--) {
|
||||
terminal_putchar(buffer[i]);
|
||||
while (i--)
|
||||
{
|
||||
terminal_putchar(buffer[i]);
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write(buffer[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_hex64(uint64_t value, int width, bool uppercase) {
|
||||
char buffer[17] = {0};
|
||||
const char* digits = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
|
||||
int i = 0;
|
||||
void print_hex64(uint64_t value, int width, bool uppercase)
|
||||
{
|
||||
char buffer[17] = {0};
|
||||
const char* digits = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
|
||||
int i = 0;
|
||||
|
||||
do {
|
||||
buffer[i++] = digits[value % 16];
|
||||
value /= 16;
|
||||
} while (value > 0);
|
||||
do
|
||||
{
|
||||
buffer[i++] = digits[value % 16];
|
||||
value /= 16;
|
||||
} while (value > 0);
|
||||
|
||||
while (i < width)
|
||||
buffer[i++] = '0';
|
||||
while (i < width)
|
||||
{
|
||||
buffer[i++] = '0';
|
||||
}
|
||||
|
||||
while (i--)
|
||||
terminal_putchar(buffer[i]);
|
||||
while (i--)
|
||||
{
|
||||
terminal_putchar(buffer[i]);
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write(buffer[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
10
lib/stdio.c
10
lib/stdio.c
@ -1,5 +1,6 @@
|
||||
#include <drivers/ps2_keyboard.h>
|
||||
#include <fs/vfs.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
@ -25,6 +26,13 @@ char* getstring(void)
|
||||
return "HELLO\0";
|
||||
}
|
||||
|
||||
char* gets(void)
|
||||
{
|
||||
return kbd_gets();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*char* fgets(char* buf, int n, FILE file)
|
||||
{
|
||||
if (!buf || n <= 1 || file < 1)
|
||||
|
||||
170
lib/string.c
170
lib/string.c
@ -4,7 +4,6 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
extern int32_t sse_initialized;
|
||||
|
||||
size_t strlen(const char* str)
|
||||
@ -184,22 +183,28 @@ char* strchr(const char* s, int c)
|
||||
}
|
||||
|
||||
|
||||
void* memset(void *dst, char c, uint32_t n)
|
||||
void* memset(void* dst, int c, size_t n)
|
||||
{
|
||||
char *temp = dst;
|
||||
for (; n != 0; n--)
|
||||
/*printf("memset(%p, %d, %u)\n", dst, c, n);*/
|
||||
|
||||
unsigned char* temp = (unsigned char*) dst;
|
||||
unsigned char val = (unsigned char) c;
|
||||
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
*temp++ = c;
|
||||
temp[i] = val;
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
void* memcpy(void *dst, const void *src, uint32_t n)
|
||||
{
|
||||
if (sse_initialized > 1)
|
||||
/*if (sse_initialized > 1)
|
||||
{
|
||||
return sse2_memcpy(dst, src, n);
|
||||
}
|
||||
}*/
|
||||
|
||||
char *d = dst;
|
||||
const char *s = src;
|
||||
@ -216,7 +221,7 @@ int32_t memcmp(const void *s1, const void *s2, size_t n)
|
||||
const uint8_t *p1 = (const uint8_t *)s1;
|
||||
const uint8_t *p2 = (const uint8_t *)s2;
|
||||
|
||||
printf("p1: %i, p2: %i\n", (int32_t)*p1, (int32_t)*p2);
|
||||
/*printf("p1: %i, p2: %i\n", (int32_t)*p1, (int32_t)*p2);*/
|
||||
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
@ -239,6 +244,34 @@ void* memclr(void* m_start, size_t m_count)
|
||||
return memset(m_start, '\0', (uint32_t)m_count);
|
||||
}
|
||||
|
||||
void* memmove(void* dest, const void* src, size_t n)
|
||||
{
|
||||
unsigned char* d = (unsigned char*) dest;
|
||||
const unsigned char* s = (const unsigned char*) src;
|
||||
|
||||
if (d == s || n == 0)
|
||||
{
|
||||
return dest;
|
||||
}
|
||||
|
||||
if (d < s)
|
||||
{
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
d[i] = s[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = n; i > 0; i--)
|
||||
{
|
||||
d[i - 1] = s[i - 1];
|
||||
}
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
int32_t isspace(char c)
|
||||
{
|
||||
return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r';
|
||||
@ -281,3 +314,124 @@ char tolower(char c)
|
||||
{
|
||||
return lower(c);
|
||||
}
|
||||
|
||||
int isprint(int c)
|
||||
{
|
||||
return (c >= 32 && c < 127);
|
||||
}
|
||||
|
||||
void lowers(char* str)
|
||||
{
|
||||
size_t len = strlen(str);
|
||||
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
str[i] = lower(str[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void uppers(char* str)
|
||||
{
|
||||
size_t len = strlen(str);
|
||||
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
str[i] = upper(str[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int atoi(const char *str)
|
||||
{
|
||||
int res = 0, sign = 1;
|
||||
|
||||
while (*str == ' ' || *str == '\t')
|
||||
{
|
||||
str++;
|
||||
}
|
||||
|
||||
if (*str == '-')
|
||||
{
|
||||
sign = -1; str++;
|
||||
}
|
||||
else if (*str == '+')
|
||||
{
|
||||
str++;
|
||||
}
|
||||
|
||||
while (*str >= '0' && *str <= '9')
|
||||
{
|
||||
res = res * 10 + (*str - '0');
|
||||
str++;
|
||||
}
|
||||
|
||||
return res * sign;
|
||||
}
|
||||
|
||||
long atol(const char *str)
|
||||
{
|
||||
long res = 0;
|
||||
int sign = 1;
|
||||
|
||||
while (*str == ' ' || *str == '\t')
|
||||
{
|
||||
str++;
|
||||
}
|
||||
|
||||
if (*str == '-')
|
||||
{
|
||||
sign = -1; str++;
|
||||
}
|
||||
else if (*str == '+')
|
||||
{
|
||||
str++;
|
||||
}
|
||||
|
||||
while (*str >= '0' && *str <= '9')
|
||||
{
|
||||
res = res * 10 + (*str - '0');
|
||||
str++;
|
||||
}
|
||||
|
||||
return res * sign;
|
||||
}
|
||||
|
||||
double atof(const char *str)
|
||||
{
|
||||
double res = 0.0, frac = 0.0;
|
||||
int sign = 1, frac_div = 1;
|
||||
|
||||
while (*str == ' ' || *str == '\t')
|
||||
{
|
||||
str++;
|
||||
}
|
||||
|
||||
if (*str == '-')
|
||||
{
|
||||
sign = -1; str++;
|
||||
}
|
||||
else if (*str == '+')
|
||||
{
|
||||
str++;
|
||||
}
|
||||
|
||||
while (*str >= '0' && *str <= '9')
|
||||
{
|
||||
res = res * 10 + (*str - '0');
|
||||
str++;
|
||||
}
|
||||
|
||||
if (*str == '.')
|
||||
{
|
||||
str++;
|
||||
|
||||
while (*str >= '0' && *str <= '9')
|
||||
{
|
||||
frac = frac * 10 + (*str - '0');
|
||||
frac_div *= 10;
|
||||
str++;
|
||||
}
|
||||
}
|
||||
|
||||
return sign * (res + frac / frac_div);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user