/** * <Ring 1> This routine handles DEV_READ and DEV_WRITE message. * * @param p Message ptr. *****************************************************************************/ PRIVATE void hd_rdwt(MESSAGE * p) { // p->DEVICE 為 0x20,也就是 hd2a int pDev = p->DEVICE; int drive = DRV_OF_DEV(p->DEVICE); u64 pos = p->POSITION; assert((pos >> SECTOR_SIZE_SHIFT) < (1 << 31)); /** * We only allow to R/W from a SECTOR boundary: */ assert((pos & 0x1FF) == 0); u32 sect_nr = (u32)(pos >> SECTOR_SIZE_SHIFT); /* pos / SECTOR_SIZE */ //取出logic index int logidx = (p->DEVICE - MINOR_hd1a) % NR_SUB_PER_DRIVE; // 找出某個partition的LBA, // MAX_PRIM=9,代表Hd0~Hd9為primary的編號,超過9以上的編號都是logic sect_nr += p->DEVICE < MAX_PRIM ? hd_info[drive].primary[p->DEVICE].base : hd_info[drive].logical[logidx].base; ERIC_HD("\nHDRW=%x", sect_nr); struct hd_cmd cmd; cmd.features = 0; cmd.count = (p->CNT + SECTOR_SIZE - 1) / SECTOR_SIZE; cmd.lba_low = sect_nr & 0xFF; cmd.lba_mid = (sect_nr >> 8) & 0xFF; cmd.lba_high= (sect_nr >> 16) & 0xFF; cmd.device = MAKE_DEVICE_REG(1, drive, (sect_nr >> 24) & 0xF); cmd.command = (p->type == DEV_READ) ? ATA_READ : ATA_WRITE; hd_cmd_out(&cmd); int bytes_left = p->CNT; void * la = (void*)va2la(p->PROC_NR, p->BUF); while (bytes_left) { //一次只讀512 byte int bytes = min(SECTOR_SIZE, bytes_left); if (p->type == DEV_READ) { interrupt_wait(); port_read(REG_DATA, hdbuf, SECTOR_SIZE); phys_copy(la, (void*)va2la(TASK_HD, hdbuf), bytes); } else { if (!waitfor(STATUS_DRQ, STATUS_DRQ, HD_TIMEOUT)) panic("hd writing error."); port_write(REG_DATA, la, bytes); interrupt_wait(); } bytes_left -= SECTOR_SIZE; la += SECTOR_SIZE; } }
/** * <Ring 1> Get the disk information. * * @param drive Drive Nr. *****************************************************************************/ PRIVATE void hd_identify(int drive) { struct hd_cmd cmd; cmd.device = MAKE_DEVICE_REG(0, drive, 0); cmd.command = ATA_IDENTIFY; hd_cmd_out(&cmd); interrupt_wait(); port_read(REG_DATA, hdbuf, SECTOR_SIZE); print_identify_info((u16*)hdbuf); }
/* * <ring 1> this routine handles DEV_READ and DEV_WRITE message. * * @param msg - message */ static void hd_rdwt(MESSAGE *msg) { int drive = DRV_OF_DEV(msg->DEVICE); u64 pos = msg->POSITION; assert((pos >> SECTOR_SIZE_SHIFT) < (1 << 31)); assert((pos & 0x1ff) == 0); u32 sect_nr = (u32)(pos >> SECTOR_SIZE_SHIFT); int logidx = (msg->DEVICE - MINOR_hd1a) % NR_SUB_PER_DRIVE; sect_nr += msg->DEVICE < MAX_PRIM ? hd_info[drive].primary[msg->DEVICE].base : hd_info[drive].logical[logidx].base; struct hd_cmd cmd; cmd.features = 0; cmd.count = (msg->CNT + SECTOR_SIZE - 1) / SECTOR_SIZE; cmd.lba_low = sect_nr & 0xff; cmd.lba_mid = (sect_nr >> 8) & 0xff; cmd.lba_high = (sect_nr >> 16) & 0xff; cmd.device = MAKE_DEVICE_REG(1, drive, (sect_nr >> 24) & 0xf); cmd.command = (msg->type == DEV_READ) ? ATA_READ : ATA_WRITE; hd_cmd_out(&cmd); int bytes_left = msg->CNT; void *la = (void*)va2la(msg->PROC_NR, msg->BUF); while (bytes_left > 0) { int bytes = min(SECTOR_SIZE, bytes_left); if (msg->type == DEV_READ) { interrupt_wait(); port_read(REG_DATA, hdbuf, SECTOR_SIZE); phys_copy(la, (void*)va2la(TASK_HD, hdbuf), bytes); } else { if (!waitfor(STATUS_DRQ, STATUS_DRQ, HD_TIMEOUT)) { panic("hd writing error."); } port_write(REG_DATA, la, bytes); interrupt_wait(); } bytes_left -= SECTOR_SIZE; la += SECTOR_SIZE; } }
/* @param drive When drive == 0, master is selected When drive == 1 slave is selected*/ PUBLIC void kernelHdIdentify(int drive) { struct hd_cmd cmd; cmd.device = MAKE_DEVICE_REG(0, drive, 0); cmd.command = ATA_IDENTIFY; hd_cmd_out(&cmd); hdIdentifyBlockEip = p_proc_running - proc_table; kernelBlock(); port_read(REG_DATA, hdbuf, SECTOR_SIZE); //analysis_identify_info((u16*)hdbuf); }
/* * <ring 1> get the disk information */ static void hd_identify(int drive) { struct hd_cmd cmd; cmd.device = MAKE_DEVICE_REG(0, drive, 0); cmd.command = ATA_INDENTIFY; hd_cmd_out(&cmd); interrupt_wait(); port_read(REG_DATA, hdbuf, SECTOR_SIZE); print_identify_info((u16*)hdbuf); u16 * hdinfo = (u16*)hdbuf; hd_info[drive].primary[0].base = 0; hd_info[drive].primary[0].size = ((int)hdinfo[61] << 16) + hdinfo[60]; }
PRIVATE void get_part_table(int drive, int sectnr, struct part_ent *entry) { struct hd_cmd cmd; cmd.features = 0; cmd.count = 1; cmd.lba_low = sect_nr & 0xff; cmd.lba_mid = (sect_nr >> 8) & 0xff; cmd.lba_high = (sect_nr >> 16) & 0xff; cmd.device = MAKE_DEVICE_REG(1, drive, (sect_nr >> 24) & 0xf); cmd.command = ATA_READ; hd_cmd_out(&cmd); interrupt_wait(); port_read(REG_DATA, hdbuf, SECTOR_SIZE); memcpy(entry, hdbuf + PARTITION_TABLE_OFFSET, sizeof (struct part_ent) * NR_PART_PER_DRIVE); }
PRIVAATE void hd_rdwt(MESSAGE *p) { int drive = DRV_OF_DEV(p->DEVICE); u64_t pos = p->POSITION; u32_t sect_nr = (u32_t)(pos >> SECTOR_SIZE_SHIFT); int logidx = (p->DEVICE - MINOR_HD1a) % NR_SUB_PER_DRIVE; sect_nr += p->DEVICE < MAX_PRIM ? hd_info[drive].primary[p->DEVICE].base : hd_info[drive].logical[logidx].base; struct hd_cmd cmd; cmd.features = 0; cmd.count = (p->CNT + SECTOR_SIZE - 1) / SECTOR_SIZE; cmd.lba_low = sect_nr & 0xff; cmd.lba_mid = (sect_nr >> 8) & 0xff; cmd.lba_high = (sect_nr >> 16) & 0xff; cmd.device = MAKE_DEVICE_REG(1, drive, (sect_nr >> 24) & 0xf); cmd.command = (p->type == DEV_READ) ? ATA_READ : ATA_WRITE; hd_cmd_out(&cmd); int bytes_left = p->CNT; void *la = (void*)va2la(p->PROC_NR, p->BUF); while (bytes_left) { int bytes = min(SECTOR_SIZE, bytes_left); if (p->type == DEV_READ) { interrupt_wait(); port_read(REG_DATA, hdbuf, SECTOR_SIZE); phys_copy(la, (void*)va2la(TASK_HD, hdbuf), bytes); } else { if (!waitfor(STATUS_DRQ, STATUS_DRQ, HD_TIMEOUT)) { kprintf("[KERNEL ERROR]hd writing error.\n"); break; } port_write(REG_DATA, la, bytes); interrupt_wait(); } bytes_left -= SECTOR_SIZE; la += SECTOR_SIZE; } }
/** * <Ring 1> Get the disk information. * * @param drive Drive Nr. *****************************************************************************/ PRIVATE void hd_identify(int drive) { struct hd_cmd cmd; cmd.device = MAKE_DEVICE_REG(0, drive, 0); cmd.command = ATA_IDENTIFY; ERIC_DEBUG(",IdTB"); hd_cmd_out(&cmd); interrupt_wait(); ERIC_DEBUG(",ReadData"); port_read(REG_DATA, hdbuf, SECTOR_SIZE); print_identify_info((u16*)hdbuf); u16* hdinfo = (u16*)hdbuf; hd_info[drive].primary[0].base = 0; /* Total Nr of User Addressable Sectors */ hd_info[drive].primary[0].size = ((int)hdinfo[61] << 16) + hdinfo[60]; }
PRIVATE void hd_identify(int drive) { HD_CMD cmd; cmd.device = MAKE_DEVICE_REG(0, drive, 0); cmd.command = ATA_IDENTIFY; /* 向硬盘发送IDENTIFY指令 */ hd_cmd_out(&cmd); interrupt_wait(); /* 中断结束 */ port_read(REG_DATA, hdbuf, SECTOR_SIZE); /* print_identify_info((u16*)hdbuf); */ u16* hdinfo = (u16*)hdbuf; hd_info[drive].primary[0].base = 0; hd_info[drive].primary[0].size = ((int)hdinfo[61] << 16) + hdinfo[60]; }
PRIVATE void get_part_table(int drive, int sect_nr, PART_ENT* entry) { HD_CMD cmd; /* 设置命令 */ cmd.features = 0; cmd.count = 1; cmd.lba_low = sect_nr & 0xFF; cmd.lba_mid = (sect_nr >> 8) & 0xFF; cmd.lba_high = (sect_nr >> 16) & 0xFF; cmd.device = MAKE_DEVICE_REG(1, drive, (sect_nr >> 24) & 0xF); /* LBA Mode */ cmd.command = ATA_READ; hd_cmd_out(&cmd); /* 等待中断发生 */ interrupt_wait(); /* 数据已经就绪 */ port_read(REG_DATA, hdbuf, SECTOR_SIZE); /* 分区表的偏移为PARTITION_TABLE_OFFSET = 0x1BE */ memcpy(entry, hdbuf + PARTITION_TABLE_OFFSET, sizeof(PART_ENT) * NR_PART_PER_DRIVE); }
PRIVATE void hd_rdwt(MESSAGE* p_msg) { int drive = DRV_OF_DEV(p_msg -> DEVICE); u64 pos = p_msg -> POSITION; assert((pos & 0x1FF) == 0); /* 只允许从扇区边界开始读 */ u32 sect_nr = (u32)(pos >> SECTOR_SIZE_SHIFT); int logidx = (p_msg -> DEVICE - MINOR_hd1a) % NR_SUB_PER_DRIVE; sect_nr += p_msg -> DEVICE < MAX_PRIM ? hd_info[drive].primary[p_msg -> DEVICE].base : hd_info[drive].logical[logidx].base; HD_CMD cmd; cmd.features = 0; cmd.count = (p_msg -> CNT + SECTOR_SIZE - 1) / SECTOR_SIZE; cmd.lba_low = sect_nr & 0xFF; cmd.lba_mid = (sect_nr >> 8) & 0xFF; cmd.lba_high = (sect_nr >> 16) & 0xFF; cmd.device = MAKE_DEVICE_REG(1, drive, (sect_nr >> 24) & 0xF); cmd.command = (p_msg -> type == DEV_READ) ? ATA_READ : ATA_WRITE; hd_cmd_out(&cmd); int bytes_left = p_msg -> CNT; void* la = (void*)va2la(p_msg -> PROC_NR, p_msg -> BUF); while (bytes_left > 0) { int bytes = min(bytes_left, SECTOR_SIZE); if (p_msg -> type == DEV_READ) { /* 一次中断一个扇区 */ interrupt_wait(); port_read(REG_DATA, hdbuf, SECTOR_SIZE); memcpy(la, (void*)va2la(TASK_HD, hdbuf), bytes); } else { if (!waitfor(STATUS_DRQ, STATUS_DRQ, HD_TIMEOUT)) panic("HD writing error"); port_write(REG_DATA, la, bytes); interrupt_wait(); } la += bytes; bytes_left -= bytes; } }
/***************************************************************************** * get_part_table ***************************************************************************** * <Ring 1> Get a partition table of a drive. * * @param drive Drive nr (0 for the 1st disk, 1 for the 2nd, ...)n * @param sect_nr The sector at which the partition table is located. * @param entry Ptr to part_ent struct. *****************************************************************************/ PRIVATE void get_part_table(int drive, int sect_nr, struct part_ent * entry) { struct hd_cmd cmd; cmd.features = 0; cmd.count = 1; cmd.lba_low = sect_nr & 0xFF; cmd.lba_mid = (sect_nr >> 8) & 0xFF; cmd.lba_high = (sect_nr >> 16) & 0xFF; cmd.device = MAKE_DEVICE_REG(1, /* LBA mode */ drive, (sect_nr >> 24) & 0xF); cmd.command = ATA_READ; hd_cmd_out(&cmd); hdIdentifyBlockEip = p_proc_running - proc_table; kernelBlock(); asm("sti"); port_read(REG_DATA, hdbuf, SECTOR_SIZE); memcpy(entry, hdbuf + PARTITION_TABLE_OFFSET, sizeof(struct part_ent) * NR_PART_PER_DRIVE); }
/** * <Ring 1> Get a partition table of a drive. * * @param drive Drive nr (0 for the 1st disk, 1 for the 2nd, ...)n * @param sect_nr The sector at which the partition table is located. * @param entry Ptr to part_ent struct. *****************************************************************************/ PRIVATE void get_part_table(int drive, int sect_nr, struct part_ent * entry) { ERIC_HD("\nGetPTable=%x", sect_nr); struct hd_cmd cmd; // ata read cmd ( 0x20 ) cmd.features = 0; cmd.count = 1; cmd.lba_low = sect_nr & 0xFF; cmd.lba_mid = (sect_nr >> 8) & 0xFF; cmd.lba_high = (sect_nr >> 16) & 0xFF; cmd.device = MAKE_DEVICE_REG(1, /* LBA mode*/ drive, (sect_nr >> 24) & 0xF); cmd.command = ATA_READ; hd_cmd_out(&cmd); interrupt_wait(); port_read(REG_DATA, hdbuf, SECTOR_SIZE); memcpy(entry, hdbuf + PARTITION_TABLE_OFFSET, sizeof(struct part_ent) * NR_PART_PER_DRIVE); }
PUBLIC void kernelHdRead(u32 device, u64 position, u32 count, char* buf) { // hd_status = in_byte(REG_STATUS); // disp_str("before hd_status="); // disp_int(hd_status); // disp_str("\n"); device = 0; int drive = DRV_OF_DEV(device); // disp_str("hdRead position: "); // disp_int(position); // if((position & 0x1FF) != 0) // disp_str("we only allow to R/W from a SECTOR boundary\n"); int offset_in_block = position & 0x1FF; u32 sect_nr = (u32)(position >> SECTOR_SIZE_SHIFT); int logidx = (device - MINOR_hd1a) % NR_SUB_PER_DRIVE; sect_nr += device < MAX_PRIM ? hd_info[drive].primary[device].base : hd_info[drive].logical[logidx].base; struct hd_cmd cmd; cmd.features = 0; cmd.count = (offset_in_block + count + SECTOR_SIZE - 1) / SECTOR_SIZE; cmd.lba_low = sect_nr & 0xFF; cmd.lba_mid = (sect_nr >> 8) & 0xFF; cmd.lba_high = (sect_nr >> 16) & 0xFF; cmd.device = MAKE_DEVICE_REG(1, drive, (sect_nr >> 24) & 0xF); cmd.command = ATA_READ; hd_cmd_out(&cmd); asm("cli"); int bytes_left = count; // disp_int(count); char** pbuf = &buf; char blockBuf[SECTOR_SIZE] = {'\0'}; int firstFlag = 1; while(bytes_left > 0){ // disp_str("in hd loop@@@"); // disp_str("hd, byte_lefs="); // disp_int(bytes_left); int bytes = ((SECTOR_SIZE - offset_in_block) < bytes_left )? (SECTOR_SIZE - offset_in_block) : bytes_left; // disp_str("hd loop,bytes="); // disp_int(bytes); // // disp_str("hd loop,beytes_left="); // disp_int(bytes_left); hdIdentifyBlockEip = p_proc_running - proc_table; kernelBlock(); port_read(REG_DATA, blockBuf, SECTOR_SIZE); if(!firstFlag) offset_in_block = 0; else firstFlag = 0; memcpy(*pbuf, &(blockBuf[offset_in_block]), bytes); bytes_left -= bytes; *pbuf += bytes; // disp_str("hd loop,beytes_left="); // disp_int(bytes_left); } }
PUBLIC void kernelHdWrite(u32 device, u64 position, u32 count, char* buf) { // disp_int((void*) kernelHdWrite); // hd_status = hd_status & 0xf7; // disp_str("after hd_status="); // disp_int(hd_status); // disp_str("\n"); // out_byte(REG_STATUS, hd_status); // hd_status = in_byte(REG_STATUS); // int drive = DRV_OF_DEV(device); // // // if((position & 0x1FF) != 0) // { // disp_str("we only allow to R/W from a SECTOR boundary\n"); // } // // u32 sect_nr = (u32)(position >> SECTOR_SIZE_SHIFT); // int logidx = (device - MINOR_hd1a) % NR_SUB_PER_DRIVE; // sect_nr += device < MAX_PRIM ? // hd_info[drive].primary[device].base : // hd_info[drive].logical[logidx].base; // // struct hd_cmd cmd; // cmd.features = 0; // cmd.count = (count + SECTOR_SIZE - 1) / SECTOR_SIZE; // disp_str("count: "); // disp_int(cmd.count); // cmd.lba_low = sect_nr & 0xFF; // disp_str("\nlba_low: "); // disp_int(cmd.lba_low); // cmd.lba_mid = (sect_nr >> 8) & 0xFF; // disp_str("\nlba_mid: "); // disp_int(cmd.lba_mid); // cmd.lba_high = (sect_nr >> 16) & 0xFF; // disp_str("\nlba_high: "); // disp_int(cmd.lba_high); // cmd.device = MAKE_DEVICE_REG(1, drive, (sect_nr >> 24) & 0xF); // disp_str("\ndevice: "); // disp_int(cmd.device); // cmd.command = ATA_WRITE; // disp_str("\ncommand: "); // disp_int(cmd.command); // disp_str("\n"); // hd_cmd_out(&cmd); // asm("sti"); // // disp_str("cmd out"); // int bytes_left = count; // while(bytes_left > 0){ // int bytes = (SECTOR_SIZE < bytes_left) ? SECTOR_SIZE : bytes_left; // // if(!waitfor(STATUS_DRQ, STATUS_DRQ, HD_TIMEOUT)) // disp_str("hd writing error.\n"); // // port_write(REG_DATA, buf, bytes); // hdIdentifyBlockEip = p_proc_running - proc_table; // disp_int(hdIdentifyBlockEip); // disp_str("before block!\n"); // asm("cli"); // kernelBlock(); // asm("sti"); // disp_str("after block!\n"); // bytes_left -= bytes; // buf += bytes; // } int drive = DRV_OF_DEV(device); u64 pos = position; u32 sect_nr = (u32)(pos >> SECTOR_SIZE_SHIFT); int logidx = (device - MINOR_hd1a) % NR_SUB_PER_DRIVE; sect_nr += device < MAX_PRIM ? hd_info[drive].primary[device].base : hd_info[drive].logical[logidx].base; struct hd_cmd cmd; cmd.features = 0; cmd.count = (count + SECTOR_SIZE - 1) / SECTOR_SIZE; cmd.lba_low = sect_nr & 0xFF; cmd.lba_mid = (sect_nr >> 8) & 0xFF; cmd.lba_high = (sect_nr >> 16) & 0xFF; cmd.device = MAKE_DEVICE_REG(1, drive, (sect_nr >> 24) & 0xF); cmd.command = ATA_WRITE; hd_cmd_out(&cmd); int bytes_left = count; while(bytes_left > 0){ int bytes = (SECTOR_SIZE < bytes_left) ? SECTOR_SIZE : bytes_left; if(!waitfor(STATUS_DRQ, STATUS_DRQ, HD_TIMEOUT)) disp_str("hd writing error.\n"); port_write(REG_DATA, buf, bytes); hdIdentifyBlockEip = p_proc_running - proc_table; kernelBlock(); bytes_left -= bytes; buf += bytes; } }