Block IO Scheduler (#158)

* Block io调度器
* process_wakeup时,对cfs的进程,重设虚拟运行时间。解决由于休眠的进程,其虚拟运行时间过小,导致其他进程饥饿的问题

* 1、为AP核启动apic_timer,使其能够运行调度
2、增加kick_cpu功能,支持让某个特定核心立即运行调度器
3、wait_queue的唤醒,改为立即唤醒。
4、增加进程在核心间迁移的功能
5、CFS调度器为每个核心设置单独的IDLE进程pcb(pid均为0)
6、pcb中增加migrate_to字段
7、当具有多核时,io调度器在核心1上运行。

* io调度器文件位置修改

* 修改io的makefile

* 更新makefile中的变量名

* 修改io调度器函数名

---------

Co-authored-by: login <longjin@ringotek.cn>
This commit is contained in:
houmkh 2023-02-04 12:31:15 +08:00 committed by GitHub
parent 151251b50b
commit f6ba114bb0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 831 additions and 264 deletions

View File

@ -17,7 +17,7 @@ export ASFLAGS := --64
LD_LIST := head.o
kernel_subdirs := common driver process debug filesystem time arch exception mm smp sched syscall ktest libs ipc
kernel_subdirs := common driver process debug filesystem time arch exception mm smp sched syscall ktest libs ipc io

View File

@ -2,17 +2,17 @@ use core::arch::asm;
/// @brief 获取当前cpu的apic id
#[inline]
pub fn arch_current_apic_id() -> u8 {
pub fn current_cpu_id() -> u8 {
let cpuid_res: u32;
unsafe {
asm!(
"mov eax, 1",
"cpuid",
"mov r15, ebx",
"mov r15, rbx",
lateout("r15") cpuid_res
);
}
return (cpuid_res >> 24) as u8;
return ((cpuid_res >> 24) & 0xff) as u8;
}
/// @brief 通过pause指令让cpu休息一会儿。降低空转功耗

View File

@ -40,11 +40,8 @@ struct block_device_request_packet
uint64_t LBA_start;
uint32_t count;
uint64_t buffer_vaddr;
uint8_t device_type; // 0: ahci
void (*end_handler)(ul num, ul arg);
wait_queue_node_t wait_queue;
};
/**
@ -53,7 +50,6 @@ struct block_device_request_packet
*/
struct block_device_request_queue
{
wait_queue_node_t wait_queue_list;
struct block_device_request_packet *in_service; // 正在请求的结点
ul request_count;
};
@ -69,7 +65,6 @@ struct block_device
sector_t bd_sectors_num; // 该分区的扇区数
struct vfs_superblock_t *bd_superblock; // 执行超级块的指针
struct blk_gendisk *bd_disk; // 当前分区所属的磁盘
struct block_device_request_queue *bd_queue; // 请求队列
uint16_t bd_partno; // 在磁盘上的分区号
};
@ -87,8 +82,6 @@ struct blk_gendisk
uint16_t flags;
struct block_device *partition; // 磁盘分区数组
const struct block_device_operation *fops; // 磁盘操作
struct block_device_request_queue *request_queue; // 磁盘请求队列
void *private_data;
mutex_t open_mutex; // open()/close()操作的互斥锁
};

View File

@ -30,7 +30,7 @@ long wait_for_completion_interruptible_timeout(struct completion *x, long timeou
void wait_for_multicompletion(struct completion x[], int n);
bool try_wait_for_completion(struct completion *x);
bool completion_done(struct completion *x);
struct completion *completion_alloc();
/**
* ()
*/

View File

@ -1,8 +1,8 @@
#pragma once
#include <common/err.h>
#include <common/numa.h>
#include <process/proc-types.h>
#include <common/err.h>
#include <process/process.h>
/**
@ -21,9 +21,7 @@ struct kthread_info_t
char *full_name; // 内核线程的名称
};
struct process_control_block *kthread_create_on_node(int (*thread_fn)(void *data),
void *data,
int node,
struct process_control_block *kthread_create_on_node(int (*thread_fn)(void *data), void *data, int node,
const char name_fmt[], ...);
/**
* @brief 线
@ -66,8 +64,10 @@ struct process_control_block *kthread_create_on_node(int (*thread_fn)(void *data
({ \
struct process_control_block *__kt = kthread_create(thread_fn, data, name_fmt, ##__VA_ARGS__); \
__kt = process_init_rt_pcb(__kt); \
if (!IS_ERR(__kt)){ \
process_wakeup(__kt);} \
if (!IS_ERR(__kt)) \
{ \
process_wakeup(__kt); \
} \
__kt; \
})

View File

@ -8,11 +8,10 @@
#include <common/block.h>
#include <filesystem/MBR.h>
#include <debug/bug.h>
#include <common/kthread.h>
struct pci_device_structure_header_t *ahci_devs[MAX_AHCI_DEVICES];
struct block_device_request_queue ahci_req_queue;
struct blk_gendisk ahci_gendisk0 = {0}; // 暂时硬性指定一个ahci_device
static int __first_port = -1; // 临时用于存储 ahci控制器的第一个可用端口 的变量
@ -24,10 +23,6 @@ static uint64_t ahci_port_base_phys_addr; // 端口映射的物理基地址ah
static void start_cmd(HBA_PORT *port);
static void stop_cmd(HBA_PORT *port);
static void port_rebase(HBA_PORT *port, int portno);
static long ahci_query_disk();
// Find a free command list slot
static int ahci_find_cmdslot(HBA_PORT *port);
// 计算HBA_MEM的虚拟内存地址
#define cal_HBA_MEM_VIRT_ADDR(device_num) (AHCI_MAPPING_BASE + (ul)(((struct pci_device_structure_general_device_t *)(ahci_devs[device_num]))->BAR5 - ((((struct pci_device_structure_general_device_t *)(ahci_devs[0]))->BAR5) & PAGE_2M_MASK)))
@ -92,7 +87,7 @@ static int ahci_init_gendisk()
ahci_gendisk0.flags = BLK_GF_AHCI;
ahci_gendisk0.fops = &ahci_operation;
mutex_init(&ahci_gendisk0.open_mutex);
ahci_gendisk0.request_queue = &ahci_req_queue;
// 为存储分区结构,分配内存空间
ahci_gendisk0.private_data = __alloc_private_data();
// 读取分区表
@ -127,7 +122,7 @@ static int ahci_init_gendisk()
// 初始化分区结构体
ahci_gendisk0.partition[cnt].bd_disk = &ahci_gendisk0;
ahci_gendisk0.partition[cnt].bd_partno = cnt;
ahci_gendisk0.partition[cnt].bd_queue = &ahci_req_queue;
// FIXME 需要注释
ahci_gendisk0.partition[cnt].bd_sectors_num = ptable->DPTE[i].total_sectors;
ahci_gendisk0.partition[cnt].bd_start_sector = ptable->DPTE[i].starting_sector;
ahci_gendisk0.partition[cnt].bd_superblock = NULL; // 挂载文件系统时才会初始化superblock
@ -175,11 +170,6 @@ void ahci_init()
kdebug("ahci_port_base_vaddr=%#018lx", ahci_port_base_vaddr);
ahci_probe_port(0);
// 初始化请求队列
ahci_req_queue.in_service = NULL;
wait_queue_init(&ahci_req_queue.wait_queue_list, NULL);
ahci_req_queue.request_count = 0;
BUG_ON(ahci_init_gendisk() != 0);
kinfo("AHCI initialized.");
}
@ -333,17 +323,23 @@ static void port_rebase(HBA_PORT *port, int portno)
* @param starth high 32bits of start addr
* @param count total sectors to read
* @param buf buffer
* @param ret_slot
* @return true done
* @return false failed
*/
static bool ahci_read(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count, uint64_t buf)
static int ahci_read(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count, uint64_t buf, int8_t *ret_slot)
{
port->is = (uint32_t)-1; // Clear pending interrupt bits
int spin = 0; // Spin lock timeout counter
int slot = ahci_find_cmdslot(port);
if (slot == -1)
return E_NOEMPTYSLOT;
if (ret_slot)
{
*ret_slot = slot;
}
HBA_CMD_HEADER *cmdheader = (HBA_CMD_HEADER *)phys_2_virt(port->clb);
cmdheader += slot;
@ -402,43 +398,59 @@ static bool ahci_read(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t
port->ci = 1 << slot; // Issue command
current_pcb->flags |= PF_NEED_SCHED;
return 0;
}
int retval = AHCI_SUCCESS;
// Wait for completion
while (1)
/**
* @brief
*
* @param port_num HBA PORT
* @param ahci_ctrl_num ahci控制号
* @param ret_slot
* @param err
*/
int ahci_check_complete(uint8_t port_num, uint8_t ahci_ctrl_num, int8_t slot, char *err)
{
HBA_PORT *port = ahci_get_port(port_num, ahci_ctrl_num);
int retval = -EBUSY;
if (slot == -1)
retval = -EINVAL;
// In some longer duration reads, it may be helpful to spin on the DPS bit
// in the PxIS port field as well (1 << 5)
if ((port->ci & (1 << slot)) == 0)
break;
retval = 0;
if (port->is & HBA_PxIS_TFES) // Task file error
{
kerror("Read disk error");
retval = E_TASK_FILE_ERROR;
break;
}
}
// Check again
if (port->is & HBA_PxIS_TFES)
{
kerror("Read disk error");
if (err != NULL)
kerror(*err);
retval = E_TASK_FILE_ERROR;
}
enter_syscall_int(SYS_AHCI_END_REQ, 0, 0, 0, 0, 0, 0, 0, 0);
return retval;
}
static bool ahci_write(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count,
uint64_t buf)
/**
* @brief write data to SATA device using 48bit LBA address
*
* @param port HBA PORT
* @param startl low 32bits of start addr
* @param starth high 32bits of start addr
* @param count total sectors to read
* @param buf buffer
* @param ret_slot
* @return success 0
*/
static int ahci_write(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count,
uint64_t buf, int8_t *ret_slot)
{
// kdebug("ahci write");
port->is = 0xffff; // Clear pending interrupt bits
int slot = ahci_find_cmdslot(port);
if (slot == -1)
return E_NOEMPTYSLOT;
if (ret_slot)
{
*ret_slot = slot;
}
HBA_CMD_HEADER *cmdheader = (HBA_CMD_HEADER *)phys_2_virt(port->clb);
cmdheader += slot;
@ -479,37 +491,13 @@ static bool ahci_write(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_
cmdfis->countl = count & 0xff;
cmdfis->counth = count >> 8;
// printk("[slot]{%d}", slot);
port->ci = 1; // Issue command
current_pcb->flags |= PF_NEED_SCHED;
int retval = AHCI_SUCCESS;
while (1)
{
// In some longer duration reads, it may be helpful to spin on the DPS bit
// in the PxIS port field as well (1 << 5)
if ((port->ci & (1 << slot)) == 0)
break;
if (port->is & HBA_PxIS_TFES)
{ // Task file error
kerror("Write disk error");
retval = E_TASK_FILE_ERROR;
break;
}
}
if (port->is & HBA_PxIS_TFES)
{
kerror("Write disk error");
retval = E_TASK_FILE_ERROR;
}
// kdebug("ahci write retval=%d", retval);
enter_syscall_int(SYS_AHCI_END_REQ, 0, 0, 0, 0, 0, 0, 0, 0);
return retval;
return 0;
}
// Find a free command list slot
static int ahci_find_cmdslot(HBA_PORT *port)
int ahci_find_cmdslot(HBA_PORT *port)
{
// If not set in SACT and CI, the slot is free
uint32_t slots = (port->sact | port->ci);
@ -547,9 +535,7 @@ long ahci_close()
*/
static struct ahci_request_packet_t *ahci_make_request(long cmd, uint64_t base_addr, uint64_t count, uint64_t buffer, uint8_t ahci_ctrl_num, uint8_t port_num)
{
struct ahci_request_packet_t *pack = (struct ahci_request_packet_t *)kmalloc(sizeof(struct ahci_request_packet_t), 0);
wait_queue_init(&pack->blk_pak.wait_queue, current_pcb);
struct ahci_request_packet_t *pack = (struct ahci_request_packet_t *)kzalloc(sizeof(struct ahci_request_packet_t), 0);
pack->blk_pak.device_type = BLK_TYPE_AHCI;
// 由于ahci不需要中断即可读取磁盘因此end handler为空
@ -572,72 +558,32 @@ static struct ahci_request_packet_t *ahci_make_request(long cmd, uint64_t base_a
pack->blk_pak.LBA_start = base_addr;
pack->blk_pak.count = count;
pack->blk_pak.buffer_vaddr = buffer;
pack->ahci_ctrl_num = ahci_ctrl_num;
pack->port_num = port_num;
return pack;
}
/**
* @brief
*
*/
void ahci_end_request()
long ahci_query_disk(struct ahci_request_packet_t *pack, int8_t *ret_slot)
{
ahci_req_queue.in_service->wait_queue.pcb->state = PROC_RUNNING;
// ahci_req_queue.in_service->wait_queue.pcb->flags |= PF_NEED_SCHED;
// current_pcb->flags |= PF_NEED_SCHED;
kfree((uint64_t *)ahci_req_queue.in_service);
ahci_req_queue.in_service = NULL;
// 进行下一轮的磁盘请求 由于未实现单独的io调度器这里会造成长时间的io等待
if (ahci_req_queue.request_count > 0)
ahci_query_disk();
}
static long ahci_query_disk()
{
wait_queue_node_t *wait_queue_tmp = container_of(list_next(&ahci_req_queue.wait_queue_list.wait_list), wait_queue_node_t, wait_list);
struct ahci_request_packet_t *pack = (struct ahci_request_packet_t *)container_of(wait_queue_tmp, struct block_device_request_packet, wait_queue);
ahci_req_queue.in_service = (struct block_device_request_packet *)pack;
list_del(&(ahci_req_queue.in_service->wait_queue.wait_list));
--ahci_req_queue.request_count;
// kdebug("ahci_query_disk");
long ret_val = 0;
switch (pack->blk_pak.cmd)
{
case AHCI_CMD_READ_DMA_EXT:
ret_val = ahci_read(&(ahci_devices[pack->ahci_ctrl_num].hba_mem->ports[pack->port_num]), pack->blk_pak.LBA_start & 0xFFFFFFFF, ((pack->blk_pak.LBA_start) >> 32) & 0xFFFFFFFF, pack->blk_pak.count, pack->blk_pak.buffer_vaddr);
ret_val = ahci_read(&(ahci_devices[pack->ahci_ctrl_num].hba_mem->ports[pack->port_num]), pack->blk_pak.LBA_start & 0xFFFFFFFF, ((pack->blk_pak.LBA_start) >> 32) & 0xFFFFFFFF, pack->blk_pak.count, pack->blk_pak.buffer_vaddr, ret_slot);
break;
case AHCI_CMD_WRITE_DMA_EXT:
ret_val = ahci_write(&(ahci_devices[pack->ahci_ctrl_num].hba_mem->ports[pack->port_num]), pack->blk_pak.LBA_start & 0xFFFFFFFF, ((pack->blk_pak.LBA_start) >> 32) & 0xFFFFFFFF, pack->blk_pak.count, pack->blk_pak.buffer_vaddr);
ret_val = ahci_write(&(ahci_devices[pack->ahci_ctrl_num].hba_mem->ports[pack->port_num]), pack->blk_pak.LBA_start & 0xFFFFFFFF, ((pack->blk_pak.LBA_start) >> 32) & 0xFFFFFFFF, pack->blk_pak.count, pack->blk_pak.buffer_vaddr, ret_slot);
break;
default:
kerror("Unsupport ahci command: %#05lx", pack->blk_pak.cmd);
ret_val = E_UNSUPPORTED_CMD;
break;
}
// kdebug("ahci_query_disk: retval=%d", ret_val);
// ahci_end_request();
return ret_val;
}
/**
* @brief io队列
*
* @param pack
*/
static void ahci_submit(struct ahci_request_packet_t *pack)
{
list_append(&(ahci_req_queue.wait_queue_list.wait_list), &(pack->blk_pak.wait_queue.wait_list));
++ahci_req_queue.request_count;
if (ahci_req_queue.in_service == NULL) // 当前没有正在请求的io包立即执行磁盘请求
ahci_query_disk();
}
/**
* @brief ahci驱动程序的传输函数
*
@ -656,10 +602,13 @@ static long ahci_transfer(struct blk_gendisk *gd, long cmd, uint64_t base_addr,
if (cmd == AHCI_CMD_READ_DMA_EXT || cmd == AHCI_CMD_WRITE_DMA_EXT)
{
pack = ahci_make_request(cmd, base_addr, count, buf, pdata->ahci_ctrl_num, pdata->ahci_port_num);
ahci_submit(pack);
ahci_push_request(pack);
}
else
{
kdebug("ahci_transfer: E_UNSUPPORTED_CMD");
return E_UNSUPPORTED_CMD;
}
return AHCI_SUCCESS;
}
@ -675,3 +624,13 @@ static long ahci_ioctl(long cmd, long arg)
{
return 0;
}
/**
* @brief
* @param port_num
* @param ahci_ctrl_num
*/
HBA_PORT *ahci_get_port(uint8_t port_num, uint8_t ahci_ctrl_num)
{
return &(ahci_devices[ahci_ctrl_num].hba_mem->ports[port_num]);
}

View File

@ -380,10 +380,10 @@ static void ahci_probe_port(const uint32_t device_num);
* @param starth high 32bits of start addr
* @param count total sectors to read
* @param buf buffer
* @return true done
* @return false failed
* @param ret_slot
* @return success 0
*/
static bool ahci_read(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count, uint64_t buf);
static int ahci_read(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count, uint64_t buf, int8_t *ret_slot);
/**
* @brief write data to SATA device using 48bit LBA address
@ -393,10 +393,40 @@ static bool ahci_read(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t
* @param starth high 32bits of start addr
* @param count total sectors to read
* @param buf buffer
* @return true done
* @return false failed
* @param ret_slot
* @return success 0
*/
static bool ahci_write(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count,
uint64_t buf);
static int ahci_write(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count,
uint64_t buf, int8_t *ret_slot);
void ahci_end_request();
/**
* @brief
*
* @param port_num HBA PORT
* @param ahci_ctrl_num ahci控制号
* @param ret_slot
* @param err
*/
int ahci_check_complete(uint8_t port_num, uint8_t ahci_ctrl_num, int8_t slot, char *err);
/**
* @brief
* @param port_num
* @param ahci_ctrl_num
*/
HBA_PORT *ahci_get_port(uint8_t port_num, uint8_t ahci_ctrl_num);
/**
* @brief Find a free command list slot
* @param port
*/
int ahci_find_cmdslot(HBA_PORT *port);
/**
* @brief
* @param pack io请求包
* @param ret_slot
*/
long ahci_query_disk(struct ahci_request_packet_t *pack, int8_t *ret_slot);

View File

@ -1,11 +1,11 @@
#include "apic.h"
#include "apic_timer.h"
#include <common/kprint.h>
#include <common/printk.h>
#include <common/cpu.h>
#include <common/glib.h>
#include <exception/gate.h>
#include <common/kprint.h>
#include <common/printk.h>
#include <driver/acpi/acpi.h>
#include <exception/gate.h>
#include <exception/softirq.h>
#include <process/process.h>
@ -62,7 +62,8 @@ void apic_io_apic_init()
// kdebug("MADT->length= %d bytes", madt->header.Length);
// 寻找io apic的ICS
void *ent = (void *)(madt_addr) + sizeof(struct acpi_Multiple_APIC_Description_Table_t);
struct apic_Interrupt_Controller_Structure_header_t *header = (struct apic_Interrupt_Controller_Structure_header_t *)ent;
struct apic_Interrupt_Controller_Structure_header_t *header =
(struct apic_Interrupt_Controller_Structure_header_t *)ent;
while (header->length > 2)
{
header = (struct apic_Interrupt_Controller_Structure_header_t *)ent;
@ -85,7 +86,8 @@ void apic_io_apic_init()
// kdebug("(ul)apic_ioapic_map.virtual_index_addr=%#018lx", (ul)apic_ioapic_map.virtual_index_addr);
// 填写页表,完成地址映射
mm_map_phys_addr((ul)apic_ioapic_map.virtual_index_addr, apic_ioapic_map.addr_phys, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false);
mm_map_phys_addr((ul)apic_ioapic_map.virtual_index_addr, apic_ioapic_map.addr_phys, PAGE_2M_SIZE,
PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false);
// 设置IO APIC ID 为0x0f000000
*apic_ioapic_map.virtual_index_addr = 0x00;
@ -99,7 +101,8 @@ void apic_io_apic_init()
// 获取IO APIC Version
*apic_ioapic_map.virtual_index_addr = 0x01;
io_mfence();
kdebug("IO APIC Version=%d, Max Redirection Entries=%d", *apic_ioapic_map.virtual_data_addr & 0xff, (((*apic_ioapic_map.virtual_data_addr) >> 16) & 0xff) + 1);
kdebug("IO APIC Version=%d, Max Redirection Entries=%d", *apic_ioapic_map.virtual_data_addr & 0xff,
(((*apic_ioapic_map.virtual_data_addr) >> 16) & 0xff) + 1);
// 初始化RTE表项将所有RTE表项屏蔽
for (int i = 0x10; i < 0x40; i += 2)
@ -171,7 +174,8 @@ static void __local_apic_xapic_init()
local_apic_max_LVT_entries = ((qword >> 16) & 0xff) + 1;
local_apic_version = qword & 0xff;
kdebug("local APIC Version:%#010x,Max LVT Entry:%#010x,SVR(Suppress EOI Broadcast):%#04x\t", local_apic_version, local_apic_max_LVT_entries, (qword >> 24) & 0x1);
kdebug("local APIC Version:%#010x,Max LVT Entry:%#010x,SVR(Suppress EOI Broadcast):%#04x\t", local_apic_version,
local_apic_max_LVT_entries, (qword >> 24) & 0x1);
if ((qword & 0xff) < 0x10)
{
@ -189,7 +193,8 @@ static void __local_apic_xapic_init()
*(uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_THERMAL) = APIC_LVT_INT_MASKED;
io_mfence();
*(uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_PERFORMANCE_MONITOR) = APIC_LVT_INT_MASKED;
*(uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_PERFORMANCE_MONITOR) =
APIC_LVT_INT_MASKED;
io_mfence();
*(uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT0) = APIC_LVT_INT_MASKED;
io_mfence();
@ -232,7 +237,8 @@ static void __local_apic_x2apic_init()
local_apic_max_LVT_entries = ((eax >> 16) & 0xff) + 1;
local_apic_version = eax & 0xff;
kdebug("local APIC Version:%#010x,Max LVT Entry:%#010x,SVR(Suppress EOI Broadcast):%#04x\t", local_apic_version, local_apic_max_LVT_entries, (eax >> 24) & 0x1);
kdebug("local APIC Version:%#010x,Max LVT Entry:%#010x,SVR(Suppress EOI Broadcast):%#04x\t", local_apic_version,
local_apic_max_LVT_entries, (eax >> 24) & 0x1);
if ((eax & 0xff) < 0x10)
kdebug("82489DX discrete APIC");
@ -269,7 +275,8 @@ void apic_local_apic_init()
uint64_t ia32_apic_base = rdmsr(0x1b);
// kdebug("apic base=%#018lx", (ia32_apic_base & 0x1FFFFFFFFFF000));
// 映射Local APIC 寄存器地址
mm_map_phys_addr(APIC_LOCAL_APIC_VIRT_BASE_ADDR, (ia32_apic_base & 0x1FFFFFFFFFFFFF), PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false);
mm_map_phys_addr(APIC_LOCAL_APIC_VIRT_BASE_ADDR, (ia32_apic_base & 0x1FFFFFFFFFFFFF), PAGE_2M_SIZE,
PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false);
uint a, b, c, d;
cpu_cpuid(1, 0, &a, &b, &c, &d);
@ -588,7 +595,8 @@ void apic_local_apic_edge_ack(ul irq_num)
uint apic_get_ics(const uint type, ul ret_vaddr[], uint *total)
{
void *ent = (void *)(madt) + sizeof(struct acpi_Multiple_APIC_Description_Table_t);
struct apic_Interrupt_Controller_Structure_header_t *header = (struct apic_Interrupt_Controller_Structure_header_t *)ent;
struct apic_Interrupt_Controller_Structure_header_t *header =
(struct apic_Interrupt_Controller_Structure_header_t *)ent;
bool flag = false;
uint cnt = 0;
@ -626,7 +634,8 @@ uint apic_get_ics(const uint type, ul ret_vaddr[], uint *total)
* @param dest_apicID apicID
*/
void apic_make_rte_entry(struct apic_IO_APIC_RTE_entry *entry, uint8_t vector, uint8_t deliver_mode, uint8_t dest_mode,
uint8_t deliver_status, uint8_t polarity, uint8_t irr, uint8_t trigger, uint8_t mask, uint8_t dest_apicID)
uint8_t deliver_status, uint8_t polarity, uint8_t irr, uint8_t trigger, uint8_t mask,
uint8_t dest_apicID)
{
entry->vector = vector;
@ -652,4 +661,35 @@ void apic_make_rte_entry(struct apic_IO_APIC_RTE_entry *entry, uint8_t vector, u
entry->destination.logical.reserved1 = 0;
}
}
/**
* @brief local apic id
*
* @return uint32_t
*/
uint32_t apic_get_local_apic_id()
{
// 获取Local APIC的基础信息 参见英特尔开发手册Vol3A 10-39
// Table 10-6. Local APIC Register Address Map Supported by x2APIC
if (flag_support_x2apic)
{
// 获取 Local APIC ID
// 0x802处是x2APIC ID 位宽32bits 的 Local APIC ID register
uint32_t x = 0;
__asm__ __volatile__("movq $0x802, %%rcx \n\t"
"rdmsr \n\t"
: "=a"(x)::"memory");
return x;
}
else
{
// kdebug("get Local APIC ID: edx=%#010x, eax=%#010x", edx, eax);
// kdebug("local_apic_id=%#018lx", );
uint32_t x = *(uint32_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_ID);
x = ((x >> 24) & 0xff);
return x;
}
}
#pragma GCC pop_options

View File

@ -330,4 +330,5 @@ void apic_local_apic_edge_ack(ul irq_num); // local apic边沿触发 应答
void apic_make_rte_entry(struct apic_IO_APIC_RTE_entry *entry, uint8_t vector, uint8_t deliver_mode, uint8_t dest_mode,
uint8_t deliver_status, uint8_t polarity, uint8_t irr, uint8_t trigger, uint8_t mask, uint8_t dest_apicID);
uint32_t apic_get_local_apic_id();
#pragma GCC pop_options

View File

@ -1,12 +1,29 @@
#include "apic_timer.h"
#include <common/kprint.h>
#include <exception/irq.h>
#include <process/process.h>
#include <common/kprint.h>
#include <sched/sched.h>
// #pragma GCC push_options
// #pragma GCC optimize("O0")
uint64_t apic_timer_ticks_result = 0;
static spinlock_t apic_timer_init_lock = {1};
// bsp 是否已经完成apic时钟初始化
static bool bsp_initialized = false;
/**
* @brief AP核的apic时钟
*
*/
void apic_timer_ap_core_init()
{
while (!bsp_initialized)
{
pause();
}
apic_timer_init();
}
void apic_timer_enable(uint64_t irq_num)
{
@ -55,8 +72,7 @@ void apic_timer_uninstall(ul irq_num)
io_mfence();
}
hardware_intr_controller apic_timer_intr_controller =
{
hardware_intr_controller apic_timer_intr_controller = {
.enable = apic_timer_enable,
.disable = apic_timer_disable,
.install = apic_timer_install,
@ -84,15 +100,23 @@ void apic_timer_handler(uint64_t number, uint64_t param, struct pt_regs *regs)
*/
void apic_timer_init()
{
if (apic_timer_ticks_result == 0)
{
kBUG("APIC timer ticks in 5ms is equal to ZERO!");
while (1)
hlt();
}
spin_lock(&apic_timer_init_lock);
kinfo("Initializing apic timer for cpu %d", proc_current_cpu_id);
io_mfence();
irq_register(APIC_TIMER_IRQ_NUM, &apic_timer_ticks_result, &apic_timer_handler, 0, &apic_timer_intr_controller, "apic timer");
irq_register(APIC_TIMER_IRQ_NUM, &apic_timer_ticks_result, &apic_timer_handler, 0, &apic_timer_intr_controller,
"apic timer");
io_mfence();
if (proc_current_cpu_id == 0)
{
bsp_initialized = true;
}
spin_unlock(&apic_timer_init_lock);
// kinfo("Successfully initialized apic timer for cpu %d", proc_current_cpu_id);
}

View File

@ -105,4 +105,6 @@ static __always_inline uint32_t apic_timer_get_current()
*/
void apic_timer_init();
void apic_timer_ap_core_init();
#pragma GCC pop_options

View File

@ -102,6 +102,8 @@ extern void (*local_apic_interrupt_table[LOCAL_APIC_IRQ_NUM])(void);
200 ~ 255 MP IPI
200 kick cpu 使
*/
typedef struct hardware_intr_type

View File

@ -372,10 +372,11 @@ find_lookup_success:; // 找到目标dentry
*/
struct vfs_superblock_t *fat32_read_superblock(struct block_device *blk)
{
// BUG
// 读取文件系统的boot扇区
uint8_t buf[512] = {0};
blk->bd_disk->fops->transfer(blk->bd_disk, AHCI_CMD_READ_DMA_EXT, blk->bd_start_LBA, 1, (uint64_t)&buf);
blk->bd_disk->fops->transfer(blk->bd_disk, AHCI_CMD_READ_DMA_EXT, blk->bd_start_LBA, 1, (uint64_t)&buf);
// 分配超级块的空间
struct vfs_superblock_t *sb_ptr = (struct vfs_superblock_t *)kzalloc(sizeof(struct vfs_superblock_t), 0);
blk->bd_superblock = sb_ptr;
@ -445,7 +446,6 @@ struct vfs_superblock_t *fat32_read_superblock(struct block_device *blk)
finode->create_date = 0;
finode->write_date = 0;
finode->write_time;
return sb_ptr;
}
@ -1411,8 +1411,6 @@ void fat32_init()
// 在VFS中注册fat32文件系统
vfs_register_filesystem(&fat32_fs_type);
// 挂载根文件系统
fat32_register_partition(ahci_gendisk0.partition + 0, 0);
kinfo("FAT32 initialized.");
}

View File

@ -10,6 +10,8 @@
*/
#pragma once
#include <common/blk_types.h>
#include <common/completion.h>
#include <common/crc16.h>
#include <common/crc32.h>
#include <common/crc64.h>
@ -18,12 +20,14 @@
#include <common/gfp.h>
#include <common/glib.h>
#include <common/kfifo.h>
#include <common/kthread.h>
#include <common/list.h>
#include <common/lz4.h>
#include <common/printk.h>
#include <common/spinlock.h>
#include <common/time.h>
#include <common/unistd.h>
#include <common/glib.h>
#include <driver/disk/ahci/ahci.h>
#include <include/DragonOS/refcount.h>
#include <include/DragonOS/signal.h>
#include <mm/mm.h>

17
kernel/src/io/Makefile Normal file
View File

@ -0,0 +1,17 @@
CFLAGS += -I .
kernel_io_subdirs:=block
ECHO:
@echo "$@"
$(kernel_io_subdirs): ECHO
$(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)" PIC="$(PIC)"
all: $(kernel_io_subdirs)
clean:
echo "Done."

View File

@ -0,0 +1,17 @@
CFLAGS += -I .
kernel_io_block_objs:= $(shell find ./*.c )
ECHO:
@echo "$@"
$(kernel_io_block_objs): ECHO
$(CC) $(CFLAGS) -c $@ -o $@.o
all: $(kernel_io_block_objs)
clean:
echo "Done."

View File

@ -0,0 +1,15 @@
#include <common/kthread.h>
#include <io/block/block_io_scheduler.h>
#include <sched/sched.h>
#include <smp/smp.h>
/**
* @brief io调度器
*/
void block_io_scheduler_init()
{
// 使用rust中的函数进行初始化
block_io_scheduler_init_rust();
struct process_control_block *pcb = kthread_run(&block_io_scheduler_address_requests, NULL, "block_io_scheduler", NULL);
if (smp_get_total_cpu() > 1)
sched_migrate_process(pcb, 1);
}

View File

@ -0,0 +1,9 @@
#pragma once
extern void block_io_scheduler_address_requests();
extern void block_io_scheduler_init_rust();
/**
* @brief io调度器
*/
void block_io_scheduler_init();

View File

@ -0,0 +1,304 @@
use core::{ptr::null_mut, sync::atomic::compiler_fence};
use alloc::{boxed::Box, vec::Vec};
use crate::{
arch::mm::barrier::mfence,
include::bindings::bindings::{
ahci_check_complete, ahci_query_disk, ahci_request_packet_t, block_device_request_packet,
complete, completion, completion_alloc, wait_for_completion,
},
kBUG,
libs::spinlock::RawSpinlock,
};
#[derive(Debug)]
/// achi请求包
pub struct AhciRequestPacket {
pub ahci_ctrl_num: u8,
pub port_num: u8,
pub slot: i8,
}
impl AhciRequestPacket {
pub fn new() -> Self {
return AhciRequestPacket {
..Default::default()
};
}
}
impl Default for AhciRequestPacket {
fn default() -> Self {
AhciRequestPacket {
ahci_ctrl_num: 0,
port_num: Default::default(),
slot: -1,
}
}
}
#[derive(Debug)]
/// io请求包
pub struct BlockDeviceRequestPacket<T> {
pub cmd: u8,
pub lba_start: u64,
pub count: u32,
pub buffer_vaddr: u64,
pub device_type: u8, // 0: ahci
pub end_handler: ::core::option::Option<
unsafe extern "C" fn(num: ::core::ffi::c_ulong, arg: ::core::ffi::c_ulong),
>,
pub private_ahci_request_packet: T,
pub status: *mut completion,
}
impl<AhciRequestPacket> BlockDeviceRequestPacket<AhciRequestPacket> {
pub fn new(
ahci_request_packet: AhciRequestPacket,
) -> BlockDeviceRequestPacket<AhciRequestPacket> {
let cmpl: *mut completion = unsafe { completion_alloc() };
return BlockDeviceRequestPacket {
cmd: Default::default(),
lba_start: Default::default(),
count: Default::default(),
buffer_vaddr: Default::default(),
device_type: Default::default(),
end_handler: Default::default(),
private_ahci_request_packet: ahci_request_packet,
status: cmpl,
};
}
}
struct RequestQueue {
lock: RawSpinlock,
waiting_queue: Vec<BlockDeviceRequestPacket<AhciRequestPacket>>,
processing_queue: Vec<BlockDeviceRequestPacket<AhciRequestPacket>>,
}
impl RequestQueue {
pub fn new() -> RequestQueue {
RequestQueue {
lock: RawSpinlock::INIT,
waiting_queue: Vec::new(),
processing_queue: Vec::new(),
}
}
/// @brief 将请求包插入等待队列中
pub fn push_waiting_queue(
&mut self,
ahci_request_packet: BlockDeviceRequestPacket<AhciRequestPacket>,
) {
self.waiting_queue.push(ahci_request_packet);
}
/// @brief 将请求包从正在执行队列中弹出
pub fn pop_waiting_queue(&mut self) -> Option<BlockDeviceRequestPacket<AhciRequestPacket>> {
let mut res: Option<BlockDeviceRequestPacket<AhciRequestPacket>> = None;
if self.waiting_queue.len() == 0 {
return res;
}
res = Some(self.waiting_queue.remove(0));
return res;
}
/// @brief 将请求包插入正在执行队列中
pub fn push_processing_queue(
&mut self,
ahci_request_packet: BlockDeviceRequestPacket<AhciRequestPacket>,
) {
self.processing_queue.push(ahci_request_packet);
}
/// @brief 将请求包从正在执行队列中弹出
pub fn pop_processing_queue(&mut self) -> Option<BlockDeviceRequestPacket<AhciRequestPacket>> {
let mut res: Option<BlockDeviceRequestPacket<AhciRequestPacket>> = None;
if self.processing_queue.len() == 0 {
return res;
}
res = Some(self.processing_queue.remove(0));
return res;
}
/// @brief 将已完成请求包从执行队列中弹出
pub fn pop_finished_packets(&mut self) {
if self.processing_queue.len() != 0 {
compiler_fence(core::sync::atomic::Ordering::SeqCst);
//将状态设置为完成
mfence();
// 过滤器,过滤已完成的请求包
let filter = |packet: &mut BlockDeviceRequestPacket<AhciRequestPacket>| {
//判断请求是否完成
let res = unsafe {
ahci_check_complete(
packet.private_ahci_request_packet.port_num,
packet.private_ahci_request_packet.ahci_ctrl_num,
packet.private_ahci_request_packet.slot,
null_mut(),
)
};
// 完成则complete请求包
if res == 0 {
unsafe {
compiler_fence(core::sync::atomic::Ordering::SeqCst);
complete(packet.status);
compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
return true;
}
return false;
};
self.processing_queue.drain_filter(filter);
mfence();
compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
}
}
pub struct SchedulerIO {
io_queue: Vec<&'static mut RequestQueue>,
}
impl SchedulerIO {
pub fn new() -> SchedulerIO {
return SchedulerIO {
io_queue: Default::default(),
};
}
}
// io调度器全局指针
pub static mut IO_SCHEDULER_PTR: *mut SchedulerIO = null_mut();
#[inline]
pub fn __get_io_scheduler() -> &'static mut SchedulerIO {
return unsafe { IO_SCHEDULER_PTR.as_mut().unwrap() };
}
/// @brief 初始化io调度器
#[no_mangle]
pub unsafe extern "C" fn block_io_scheduler_init_rust() {
if IO_SCHEDULER_PTR.is_null() {
IO_SCHEDULER_PTR = Box::leak(Box::new(SchedulerIO::new()));
create_io_queue();
} else {
kBUG!("Try to init IO Scheduler twice.");
panic!("Try to init IO Scheduler twice.");
}
}
/// @brief 初始化io请求队列
#[no_mangle]
pub extern "C" fn create_io_queue() {
let io_scheduler = __get_io_scheduler();
io_scheduler
.io_queue
.push(Box::leak(Box::new(RequestQueue::new())));
}
#[no_mangle]
/// @brief 处理请求 (守护线程运行)
pub extern "C" fn block_io_scheduler_address_requests() {
let io_scheduler = __get_io_scheduler();
compiler_fence(core::sync::atomic::Ordering::SeqCst);
//FIXME 暂时只考虑了一个io队列的情况
loop {
compiler_fence(core::sync::atomic::Ordering::SeqCst);
//请不要修改下面三个循环的顺序
let size = io_scheduler.io_queue[0].waiting_queue.len();
for i in 0..16 {
// 正在运行队列大小限制为16
if i >= size || io_scheduler.io_queue[0].processing_queue.len() == 16 {
break;
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
// if !io_scheduler.io_queue[0].lock.is_locked() {
io_scheduler.io_queue[0].lock.lock();
let mut packet = io_scheduler.io_queue[0].pop_waiting_queue().unwrap();
//将rust中的请求包转成c中的请求包
let mut ahci_packet: ahci_request_packet_t = convert_c_ahci_request(&packet);
let mut ret_slot: i8 = -1;
//分发请求包
unsafe {
compiler_fence(core::sync::atomic::Ordering::SeqCst);
ahci_query_disk(&mut ahci_packet, &mut ret_slot);
compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
//获取请求运行的插槽
packet.private_ahci_request_packet.slot = ret_slot;
io_scheduler.io_queue[0].push_processing_queue(packet);
io_scheduler.io_queue[0].lock.unlock();
// }
compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
//检查是否有完成的请求包
io_scheduler.io_queue[0].lock.lock();
io_scheduler.io_queue[0].pop_finished_packets();
io_scheduler.io_queue[0].lock.unlock();
mfence();
compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
}
pub fn convert_c_ahci_request(
pakcet: &BlockDeviceRequestPacket<AhciRequestPacket>,
) -> ahci_request_packet_t {
let ahci_packet: ahci_request_packet_t = ahci_request_packet_t {
ahci_ctrl_num: pakcet.private_ahci_request_packet.ahci_ctrl_num,
port_num: pakcet.private_ahci_request_packet.port_num,
blk_pak: block_device_request_packet {
LBA_start: pakcet.lba_start,
cmd: pakcet.cmd,
buffer_vaddr: pakcet.buffer_vaddr,
count: pakcet.count,
device_type: pakcet.device_type,
end_handler: pakcet.end_handler,
},
};
return ahci_packet;
}
/// @brief 将c中的ahci_request_packet_t转换成rust中的BlockDeviceRequestPacket<AhciRequestPacket>
pub fn create_ahci_request(
ahci_request_packet: &ahci_request_packet_t,
) -> BlockDeviceRequestPacket<AhciRequestPacket> {
let cmpl: *mut completion = unsafe { completion_alloc() };
let ahci_packet = AhciRequestPacket {
ahci_ctrl_num: ahci_request_packet.ahci_ctrl_num,
port_num: ahci_request_packet.port_num,
slot: -1,
};
let packet = BlockDeviceRequestPacket {
private_ahci_request_packet: ahci_packet,
buffer_vaddr: ahci_request_packet.blk_pak.buffer_vaddr,
cmd: ahci_request_packet.blk_pak.cmd,
count: ahci_request_packet.blk_pak.count,
device_type: ahci_request_packet.blk_pak.device_type,
end_handler: ahci_request_packet.blk_pak.end_handler,
lba_start: ahci_request_packet.blk_pak.LBA_start,
status: cmpl,
};
return packet;
}
#[no_mangle]
/// @brief 将ahci的io请求插入等待队列中
pub extern "C" fn ahci_push_request(ahci_request_packet: &ahci_request_packet_t) {
let packet = create_ahci_request(ahci_request_packet);
let io_scheduler = __get_io_scheduler();
let status = packet.status;
io_scheduler.io_queue[0].lock.lock();
io_scheduler.io_queue[0].push_waiting_queue(packet);
io_scheduler.io_queue[0].lock.unlock();
compiler_fence(core::sync::atomic::Ordering::SeqCst);
unsafe {
wait_for_completion(status);
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
}

View File

@ -0,0 +1 @@
pub mod block_io_scheduler;

1
kernel/src/io/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod block;

View File

@ -25,6 +25,7 @@ mod ipc;
#[macro_use]
mod libs;
mod exception;
pub mod io;
mod mm;
mod process;
mod sched;

View File

@ -35,10 +35,6 @@ void semaphore_up(semaphore_t *sema)
wait_queue_node_t *wq = container_of(list_next(&sema->wait_queue.wait_list), wait_queue_node_t, wait_list);
list_del(&wq->wait_list);
wq->pcb->state = PROC_RUNNING;
sched_enqueue(wq->pcb);
// 当前进程缺少需要的资源,立即标为需要被调度
current_pcb->flags |= PF_NEED_SCHED;
process_wakeup_immediately(wq->pcb);
}
};

View File

@ -138,7 +138,6 @@ impl RawSpinlock {
self.unlock();
local_irq_restore(flags);
}
}
/// 实现了守卫的SpinLock, 能够支持内部可变性
///

View File

@ -77,6 +77,6 @@ void wait_queue_wakeup_on_stack(wait_queue_head_t *q, int64_t state)
if (wait->pcb->state & state)
{
list_del_init(&wait->wait_list);
process_wakeup(wait->pcb);
process_wakeup_immediately(wait->pcb);
}
}

View File

@ -1,9 +1,9 @@
#pragma once
#include <DragonOS/signal.h>
#include <common/wait_queue.h>
#include <DragonOS/stdint.h>
#include "ptrace.h"
#include <DragonOS/signal.h>
#include <DragonOS/stdint.h>
#include <common/wait_queue.h>
// 进程最大可拥有的文件描述符数量
#define PROC_MAX_FD_NUM 16
@ -69,6 +69,8 @@ struct thread_struct
#define PF_EXITING (1UL << 5) // 进程正在退出
#define PF_WAKEKILL (1UL << 6) // 进程由于接收到终止信号唤醒
#define PF_SIGNALED (1UL << 7) // 进程由于接收到信号而退出
#define PF_NEED_MIGRATE (1UL << 8) // 进程需要迁移到其他的核心
/**
* @brief
*
@ -82,6 +84,7 @@ struct process_control_block
int32_t preempt_count; // 持有的自旋锁的数量
uint32_t cpu_id; // 当前进程在哪个CPU核心上运行
// pcb的名字
char name[PCB_NAME_LEN];
// 内存空间分布结构体, 记录内存页表和程序段信息
@ -131,6 +134,9 @@ struct process_control_block
// 正在等待的信号的标志位,表示某个信号正在等待处理
struct sigpending sig_pending;
// 如果当前进程等待被迁移到另一个cpu核心上也就是flags中的PF_NEED_MIGRATE被置位
// 该字段存储要被迁移到的目标处理器核心号
uint32_t migrate_to;
};
// 将进程的pcb和内核栈融合到一起,8字节对齐

View File

@ -6,6 +6,7 @@
#include <common/elf.h>
#include <common/kprint.h>
#include <common/kthread.h>
#include <common/lz4.h>
#include <common/printk.h>
#include <common/spinlock.h>
#include <common/stdio.h>
@ -23,15 +24,13 @@
#include <filesystem/fat32/fat32.h>
#include <filesystem/procfs/procfs.h>
#include <filesystem/rootfs/rootfs.h>
#include <io/block/block_io_scheduler.h>
#include <ktest/ktest.h>
#include <mm/mmio.h>
#include <mm/slab.h>
#include <sched/sched.h>
#include <syscall/syscall.h>
#include <syscall/syscall_num.h>
#include <mm/mmio.h>
#include <common/lz4.h>
extern int __rust_demo_func();
// #pragma GCC push_options
// #pragma GCC optimize("O0")
@ -499,6 +498,7 @@ ul initial_kernel_thread(ul arg)
scm_enable_double_buffer();
block_io_scheduler_init();
ahci_init();
fat32_init();
rootfs_umount();
@ -529,7 +529,6 @@ ul initial_kernel_thread(ul arg)
// struct process_control_block *test_rt1 = kthread_run_rt(&test, NULL, "test rt");
// kdebug("process:rt test kthread is created!!!!");
// 准备切换到用户态
struct pt_regs *regs;
@ -649,11 +648,6 @@ void process_init()
initial_tss[proc_current_cpu_id].rsp0 = initial_thread.rbp;
/*
kdebug("initial_thread.rbp=%#018lx", initial_thread.rbp);
kdebug("initial_tss[0].rsp1=%#018lx", initial_tss[0].rsp1);
kdebug("initial_tss[0].ist1=%#018lx", initial_tss[0].ist1);
*/
// 初始化pid的写锁
spin_init(&process_global_pid_write_lock);
@ -714,7 +708,6 @@ struct process_control_block *process_find_pcb_by_pid(pid_t pid)
*/
int process_wakeup(struct process_control_block *pcb)
{
// kdebug("pcb pid = %#018lx", pcb->pid);
BUG_ON(pcb == NULL);
if (pcb == NULL)
@ -724,8 +717,8 @@ int process_wakeup(struct process_control_block *pcb)
return 0;
pcb->state |= PROC_RUNNING;
sched_enqueue(pcb);
return 1;
sched_enqueue(pcb, true);
return 0;
}
/**
@ -742,6 +735,12 @@ int process_wakeup_immediately(struct process_control_block *pcb)
return retval;
// 将当前进程标志为需要调度缩短新进程被wakeup的时间
current_pcb->flags |= PF_NEED_SCHED;
if (pcb->cpu_id == current_pcb->cpu_id)
sched();
else
kick_cpu(pcb->cpu_id);
return 0;
}
/**
@ -802,7 +801,6 @@ uint64_t process_exit_mm(struct process_control_block *pcb)
vma = cur_vma->vm_next;
uint64_t pa;
// kdebug("vm start=%#018lx, sem=%d", cur_vma->vm_start, cur_vma->anon_vma->sem.counter);
mm_unmap_vma(pcb->mm, cur_vma, &pa);
uint64_t size = (cur_vma->vm_end - cur_vma->vm_start);
@ -876,7 +874,6 @@ int process_fd_alloc(struct vfs_file_t *file)
for (int i = 0; i < PROC_MAX_FD_NUM; ++i)
{
// kdebug("currentpcb->fds[%d]=%#018lx", i, current_pcb->fds[i]);
/* 找到指针数组中的空位 */
if (current_pcb->fds[i] == NULL)
{

View File

@ -56,8 +56,9 @@ pub extern "C" fn process_try_to_wake_up(
// 可以wakeup
unsafe {
write_volatile(&mut pcb.state, PROC_RUNNING as u64);
sched_enqueue(pcb);
}
sched_enqueue(pcb, true);
retval = true;
}
// todo: 对pcb的pi_lock放锁

View File

@ -9,6 +9,7 @@ use crate::{
},
kBUG,
libs::spinlock::RawSpinlock,
smp::core::smp_get_processor_id,
};
use super::core::{sched_enqueue, Scheduler};
@ -42,14 +43,17 @@ struct CFSQueue {
lock: RawSpinlock,
/// 进程的队列
queue: Vec<&'static mut process_control_block>,
/// 当前核心的队列专属的IDLE进程的pcb
idle_pcb: *mut process_control_block,
}
impl CFSQueue {
pub fn new() -> CFSQueue {
pub fn new(idle_pcb: *mut process_control_block) -> CFSQueue {
CFSQueue {
cpu_exec_proc_jiffies: 0,
lock: RawSpinlock::INIT,
queue: Vec::new(),
idle_pcb: idle_pcb,
}
}
@ -83,11 +87,22 @@ impl CFSQueue {
res = self.queue.pop().unwrap();
} else {
// 如果队列为空则返回IDLE进程的pcb
res = unsafe { &mut initial_proc_union.pcb };
res = unsafe { self.idle_pcb.as_mut().unwrap() };
}
self.lock.unlock();
return res;
}
/// @brief 获取cfs队列的最小运行时间
///
/// @return Option<i64> 如果队列不为空那么返回队列中最小的虚拟运行时间否则返回None
pub fn min_vruntime(&self) -> Option<i64> {
if !self.queue.is_empty() {
return Some(self.queue.first().unwrap().virtual_runtime);
} else {
return None;
}
}
}
/// @brief CFS调度器类
@ -105,8 +120,12 @@ impl SchedulerCFS {
// 为每个cpu核心创建队列
for _ in 0..MAX_CPU_NUM {
result.cpu_queue.push(Box::leak(Box::new(CFSQueue::new())));
result
.cpu_queue
.push(Box::leak(Box::new(CFSQueue::new(null_mut()))));
}
// 设置cpu0的pcb
result.cpu_queue[0].idle_pcb = unsafe { &mut initial_proc_union.pcb };
return result;
}
@ -137,6 +156,22 @@ impl SchedulerCFS {
// 更新当前进程的虚拟运行时间
current_pcb().virtual_runtime += 1;
}
/// @brief 将进程加入cpu的cfs调度队列并且重设其虚拟运行时间为当前队列的最小值
pub fn enqueue_reset_vruntime(&mut self, pcb: &'static mut process_control_block) {
let cpu_queue = &mut self.cpu_queue[pcb.cpu_id as usize];
if cpu_queue.queue.len() > 0 {
pcb.virtual_runtime = cpu_queue.min_vruntime().unwrap();
}
cpu_queue.enqueue(pcb);
}
/// @brief 设置cpu的队列的IDLE进程的pcb
pub fn set_cpu_idle(&mut self, cpu_id: usize, pcb: *mut process_control_block) {
// kdebug!("set cpu idle: id={}", cpu_id);
self.cpu_queue[cpu_id].idle_pcb = pcb;
}
}
impl Scheduler for SchedulerCFS {
@ -144,7 +179,8 @@ impl Scheduler for SchedulerCFS {
/// 请注意,进入该函数之前,需要关中断
fn sched(&mut self) -> Option<&'static mut process_control_block> {
current_pcb().flags &= !(PF_NEED_SCHED as u64);
let current_cpu_id = current_pcb().cpu_id as usize;
let current_cpu_id = smp_get_processor_id() as usize;
let current_cpu_queue: &mut CFSQueue = self.cpu_queue[current_cpu_id];
let proc: &'static mut process_control_block = current_cpu_queue.dequeue();
compiler_fence(core::sync::atomic::Ordering::SeqCst);
@ -155,7 +191,7 @@ impl Scheduler for SchedulerCFS {
compiler_fence(core::sync::atomic::Ordering::SeqCst);
// 本次切换由于时间片到期引发,则再次加入就绪队列,否则交由其它功能模块进行管理
if current_pcb().state & (PROC_RUNNING as u64) != 0 {
sched_enqueue(current_pcb());
sched_enqueue(current_pcb(), false);
compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
@ -166,6 +202,7 @@ impl Scheduler for SchedulerCFS {
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
return Some(proc);
} else {
// 不进行切换
@ -177,7 +214,7 @@ impl Scheduler for SchedulerCFS {
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
sched_enqueue(proc);
sched_enqueue(proc, false);
compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);

View File

@ -326,3 +326,13 @@ void __test_completion()
kfree(worker_data);
// kdebug("completion test done.");
}
/**
* @brief rust completion
*/
struct completion *completion_alloc()
{
struct completion *cmpl = kzalloc(sizeof(struct completion), 0);
completion_init(cmpl);
return cmpl;
}

View File

@ -2,11 +2,14 @@ use core::sync::atomic::compiler_fence;
use crate::{
arch::asm::{current::current_pcb, ptrace::user_mode},
arch::context::switch_process,
include::bindings::bindings::{
process_control_block, pt_regs, EPERM, PROC_RUNNING, SCHED_FIFO, SCHED_NORMAL, SCHED_RR,
arch::{
context::switch_process,
interrupt::{cli, sti},
},
include::bindings::bindings::{
process_control_block, pt_regs, EINVAL, EPERM, MAX_CPU_NUM, PF_NEED_MIGRATE, PROC_RUNNING,
SCHED_FIFO, SCHED_NORMAL, SCHED_RR,
},
kdebug,
process::process::process_cpu,
};
@ -46,7 +49,7 @@ fn __sched() -> Option<&'static mut process_control_block> {
next = p;
// kdebug!("next pcb is {}",next.pid);
// rt_scheduler.enqueue_task_rt(next.priority as usize, next);
sched_enqueue(next);
sched_enqueue(next, false);
return rt_scheduler.sched();
}
None => {
@ -56,17 +59,34 @@ fn __sched() -> Option<&'static mut process_control_block> {
}
/// @brief 将进程加入调度队列
///
/// @param pcb 要被加入队列的pcb
/// @param reset_time 是否重置虚拟运行时间
#[allow(dead_code)]
#[no_mangle]
pub extern "C" fn sched_enqueue(pcb: &'static mut process_control_block) {
pub extern "C" fn sched_enqueue(pcb: &'static mut process_control_block, mut reset_time: bool) {
// 调度器不处理running位为0的进程
if pcb.state & (PROC_RUNNING as u64) == 0 {
return;
}
let cfs_scheduler = __get_cfs_scheduler();
let rt_scheduler = __get_rt_scheduler();
compiler_fence(core::sync::atomic::Ordering::SeqCst);
if (pcb.flags & (PF_NEED_MIGRATE as u64)) != 0 {
// kdebug!("migrating pcb:{:?}", pcb);
pcb.flags &= !(PF_NEED_MIGRATE as u64);
pcb.cpu_id = pcb.migrate_to;
reset_time = true;
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
if pcb.policy == SCHED_NORMAL {
if reset_time {
cfs_scheduler.enqueue_reset_vruntime(pcb);
} else {
cfs_scheduler.enqueue(pcb);
}
} else if pcb.policy == SCHED_FIFO || pcb.policy == SCHED_RR {
rt_scheduler.enqueue(pcb);
} else {
@ -107,6 +127,7 @@ pub extern "C" fn sched_update_jiffies() {
#[allow(dead_code)]
#[no_mangle]
pub extern "C" fn sys_sched(regs: &'static mut pt_regs) -> u64 {
cli();
// 进行权限校验,拒绝用户态发起调度
if user_mode(regs) {
return (-(EPERM as i64)) as u64;
@ -116,5 +137,33 @@ pub extern "C" fn sys_sched(regs: &'static mut pt_regs) -> u64 {
if pcb.is_some() {
switch_process(current_pcb(), pcb.unwrap());
}
0
sti();
return 0;
}
#[allow(dead_code)]
#[no_mangle]
pub extern "C" fn sched_set_cpu_idle(cpu_id: usize, pcb: *mut process_control_block) {
__get_cfs_scheduler().set_cpu_idle(cpu_id, pcb);
}
/// @brief 设置进程需要等待迁移到另一个cpu核心。
/// 当进程被重新加入队列时将会更新其cpu_id,并加入正确的队列
///
/// @return i32 成功返回0,否则返回posix错误码
#[allow(dead_code)]
#[no_mangle]
pub extern "C" fn sched_migrate_process(
pcb: &'static mut process_control_block,
target: usize,
) -> i32 {
if target > MAX_CPU_NUM.try_into().unwrap() {
// panic!("sched_migrate_process: target > MAX_CPU_NUM");
return -(EINVAL as i32);
}
pcb.flags |= PF_NEED_MIGRATE as u64;
pcb.migrate_to = target as u32;
// kdebug!("pid:{} migrate to cpu:{}", pcb.pid, target);
return 0;
}

View File

@ -4,10 +4,7 @@ use alloc::{boxed::Box, vec::Vec};
use crate::{
arch::asm::current::current_pcb,
include::bindings::bindings::{
initial_proc_union, process_control_block, PF_NEED_SCHED, SCHED_FIFO, SCHED_NORMAL,
SCHED_RR,
},
include::bindings::bindings::{process_control_block, PF_NEED_SCHED, SCHED_FIFO, SCHED_RR},
kBUG, kdebug,
libs::spinlock::RawSpinlock,
};
@ -78,7 +75,6 @@ impl RTQueue {
self.lock.unlock();
return res;
}
}
/// @brief RT调度器类
@ -132,10 +128,10 @@ impl Scheduler for SchedulerRT {
if proc.policy == SCHED_FIFO {
// 如果挑选的进程优先级小于当前进程,则不进行切换
if proc.priority <= current_pcb().priority {
sched_enqueue(proc);
sched_enqueue(proc, false);
} else {
// 将当前的进程加进队列
sched_enqueue(current_pcb());
sched_enqueue(current_pcb(), false);
compiler_fence(core::sync::atomic::Ordering::SeqCst);
return Some(proc);
}
@ -148,19 +144,19 @@ impl Scheduler for SchedulerRT {
if proc.rt_time_slice <= 0 {
proc.rt_time_slice = SchedulerRT::RR_TIMESLICE;
proc.flags |= !(PF_NEED_SCHED as u64);
sched_enqueue(proc);
sched_enqueue(proc, false);
}
// 目标进程时间片未耗尽,切换到目标进程
else {
// 将当前进程加进队列
sched_enqueue(current_pcb());
sched_enqueue(current_pcb(), false);
compiler_fence(core::sync::atomic::Ordering::SeqCst);
return Some(proc);
}
}
// curr优先级更大说明一定是实时进程将所选进程入队列
else {
sched_enqueue(proc);
sched_enqueue(proc, false);
}
}
return None;

View File

@ -62,6 +62,8 @@
extern void sched_update_jiffies();
extern void sched_init();
extern void sched();
extern void sched_enqueue(struct process_control_block *pcb);
extern void sched_enqueue(struct process_control_block *pcb, bool reset_time);
extern void sched_set_cpu_idle(uint64_t cpu_id, struct process_control_block *pcb);
extern void sched_migrate_process(struct process_control_block *pcb, uint64_t target);
void switch_proc(struct process_control_block *prev, struct process_control_block *proc);

View File

@ -1,11 +1,7 @@
/// @brief 获取当前的cpu id
#[inline]
pub fn smp_get_processor_id() -> u32 {
if cfg!(x86_64) {
return crate::arch::cpu::arch_current_apic_id() as u32;
} else {
255
}
return crate::arch::cpu::current_cpu_id() as u32;
}
#[inline]

View File

@ -12,13 +12,18 @@
#include "ipi.h"
static void __smp_kick_cpu_handler(uint64_t irq_num, uint64_t param, struct pt_regs *regs);
static spinlock_t multi_core_starting_lock = {1}; // 多核启动锁
static struct acpi_Processor_Local_APIC_Structure_t *proc_local_apic_structs[MAX_SUPPORTED_PROCESSOR_NUM];
static uint32_t total_processor_num = 0;
int current_starting_cpu = 0;
static int current_starting_cpu = 0;
int num_cpu_started = 1;
static int num_cpu_started = 1;
// kick cpu 功能所使用的中断向量号
#define KICK_CPU_IRQ_NUM 0xc8
void smp_init()
{
@ -49,7 +54,10 @@ void smp_init()
ipi_send_IPI(DEST_PHYSICAL, IDLE, ICR_LEVEL_DE_ASSERT, EDGE_TRIGGER, 0x00, ICR_INIT, ICR_ALL_EXCLUDE_Self, 0x00);
kdebug("total_processor_num=%d", total_processor_num);
kdebug("rflags=%#018lx", get_rflags());
// 注册接收kick_cpu功能的处理函数。向量号200
ipi_regiserIPI(KICK_CPU_IRQ_NUM, NULL, &__smp_kick_cpu_handler, NULL, NULL, "IPI kick cpu");
int core_to_start = 0;
// total_processor_num = 3;
for (int i = 0; i < total_processor_num; ++i) // i从1开始不初始化bsp
{
@ -61,15 +69,16 @@ void smp_init()
proc_local_apic_structs[i]->flags);
if (proc_local_apic_structs[i]->local_apic_id == 0)
{
--total_processor_num;
// --total_processor_num;
continue;
}
if (!((proc_local_apic_structs[i]->flags & 0x1) || (proc_local_apic_structs[i]->flags & 0x2)))
{
--total_processor_num;
// --total_processor_num;
kdebug("processor %d cannot be enabled.", proc_local_apic_structs[i]->ACPI_Processor_UID);
continue;
}
++core_to_start;
// continue;
io_mfence();
spin_lock(&multi_core_starting_lock);
@ -114,7 +123,7 @@ void smp_init()
proc_local_apic_structs[i]->local_apic_id);
}
io_mfence();
while (num_cpu_started != total_processor_num)
while (num_cpu_started != (core_to_start + 1))
pause();
kinfo("Cleaning page table remapping...\n");
@ -162,8 +171,8 @@ void smp_ap_start()
current_pcb->virtual_runtime = 0;
current_pcb->thread = (struct thread_struct *)(current_pcb + 1); // 将线程结构体放置在pcb后方
current_pcb->thread->rbp = _stack_start;
current_pcb->thread->rsp = _stack_start;
current_pcb->thread->rbp = cpu_core_info[current_starting_cpu].stack_start;
current_pcb->thread->rsp = cpu_core_info[current_starting_cpu].stack_start;
current_pcb->thread->fs = KERNEL_DS;
current_pcb->thread->gs = KERNEL_DS;
current_pcb->cpu_id = current_starting_cpu;
@ -173,14 +182,22 @@ void smp_ap_start()
load_TR(10 + current_starting_cpu * 2);
current_pcb->preempt_count = 0;
sched_set_cpu_idle(current_starting_cpu, current_pcb);
io_mfence();
spin_unlock(&multi_core_starting_lock);
preempt_disable(); // 由于ap处理器的pcb与bsp的不同因此ap处理器放锁时需要手动恢复preempt count
io_mfence();
current_pcb->flags |= PF_NEED_SCHED;
sti();
apic_timer_ap_core_init();
sched();
while (1)
{
// kdebug("123");
hlt();
}
while (1)
{
@ -189,3 +206,43 @@ void smp_ap_start()
while (1) // 这里要循环hlt原因是当收到中断后核心会被唤醒处理完中断之后不会自动hlt
hlt();
}
/**
* @brief kick_cpu
*
* @param irq_num
* @param param
* @param regs
*/
static void __smp_kick_cpu_handler(uint64_t irq_num, uint64_t param, struct pt_regs *regs)
{
if (user_mode(regs))
return;
sched();
}
/**
* @brief 使cpu核心立即运行调度
*
* @param cpu_id cpu核心号
*/
int kick_cpu(uint32_t cpu_id)
{
if (cpu_id >= MAX_CPU_NUM)
{
return -EINVAL;
}
ipi_send_IPI(DEST_PHYSICAL, IDLE, ICR_LEVEL_DE_ASSERT, EDGE_TRIGGER, KICK_CPU_IRQ_NUM, ICR_APIC_FIXED,
ICR_ALL_EXCLUDE_Self, 0);
return 0;
}
/**
* @brief cpu数目
*
* @return uint32_t
*/
uint32_t smp_get_total_cpu()
{
return num_cpu_started;
}

View File

@ -16,3 +16,7 @@ extern uchar _apu_boot_end[];
*
*/
void smp_init();
int kick_cpu(uint32_t cpu_id);
uint32_t smp_get_total_cpu();

View File

@ -578,7 +578,7 @@ uint64_t sys_nanosleep(struct pt_regs *regs)
ul sys_ahci_end_req(struct pt_regs *regs)
{
ahci_end_request();
// ahci_end_request();
return 0;
}
@ -619,6 +619,5 @@ system_call_t system_call_table[MAX_SYSTEM_CALL_NUM] = {
[25] = sys_rt_sigreturn,
[26] = sys_getpid,
[27] = sys_sched,
[28 ... 254] = system_call_not_exists,
[255] = sys_ahci_end_req,
[28 ... 255] = system_call_not_exists,
};